1212
1313namespace Koded \Http ;
1414
15+ use InvalidArgumentException ;
16+ use Throwable ;
17+
1518
1619trait HeaderTrait
1720{
18-
1921 /**
2022 * @var array Message headers.
2123 */
@@ -52,9 +54,11 @@ public function getHeaderLine($name): string
5254 public function withHeader ($ name , $ value ): self
5355 {
5456 $ instance = clone $ this ;
57+ $ name = $ instance ->normalizeHeaderName ($ name );
5558
5659 $ instance ->headersMap [strtolower ($ name )] = $ name ;
57- $ instance ->headers [$ name ] = (array )$ value ;
60+
61+ $ instance ->headers [$ name ] = $ this ->normalizeHeaderValue ($ name , $ value );
5862
5963 return $ instance ;
6064 }
@@ -73,22 +77,24 @@ public function withHeaders(array $headers): self
7377 public function withoutHeader ($ name ): self
7478 {
7579 $ instance = clone $ this ;
76- $ key = strtolower ($ name );
77- unset($ instance ->headersMap [$ key ] , $ instance ->headers [ $ this -> headersMap [$ key ] ]);
80+ $ name = strtolower ($ name );
81+ unset($ instance ->headers [ $ this -> headersMap [$ name ]] , $ instance ->headersMap [$ name ]);
7882
7983 return $ instance ;
8084 }
8185
8286 public function withAddedHeader ($ name , $ value ): self
8387 {
84- $ value = (array )$ value ;
8588 $ instance = clone $ this ;
89+ $ name = $ instance ->normalizeHeaderName ($ name );
90+ $ value = $ instance ->normalizeHeaderValue ($ name , $ value );
8691
8792 if (isset ($ instance ->headersMap [$ header = strtolower ($ name )])) {
88- $ instance ->headers [$ name ] = array_unique (array_merge ((array )$ this ->headers [$ name ], $ value ));
93+ $ header = $ instance ->headersMap [$ header ];
94+ $ instance ->headers [$ header ] = array_unique (array_merge ((array )$ instance ->headers [$ header ], $ value ));
8995 } else {
90- $ instance ->headersMap [strtolower ( $ name ) ] = $ name ;
91- $ instance ->headers [$ name ] = $ value ;
96+ $ instance ->headersMap [$ header ] = $ name ;
97+ $ instance ->headers [$ name ] = $ value ;
9298 }
9399
94100 return $ instance ;
@@ -149,22 +155,22 @@ public function getCanonicalizedHeaders(array $names = []): string
149155
150156 /**
151157 * @param string $name
152- * @param string $value
158+ * @param mixed $value
153159 * @param bool $skipKey
154160 *
155161 * @return void
156162 */
157163 protected function normalizeHeader (string $ name , $ value , bool $ skipKey ): void
158164 {
159- $ name = trim ($ name );
165+ $ name = str_replace ([ "\r" , "\n" , "\t" ], '' , trim ($ name) );
160166
161167 if (false === $ skipKey ) {
162168 $ name = ucwords (str_replace ('_ ' , '- ' , strtolower ($ name )), '- ' );
163169 }
164170
165171 $ this ->headersMap [strtolower ($ name )] = $ name ;
166172
167- $ this ->headers [$ name ] = array_map ( ' trim ' , ( array ) $ value );
173+ $ this ->headers [$ name ] = $ this -> normalizeHeaderValue ( $ name , $ value );
168174 }
169175
170176 /**
@@ -180,4 +186,59 @@ protected function setHeaders(array $headers)
180186
181187 return $ this ;
182188 }
189+
190+ /**
191+ * @param string $name
192+ *
193+ * @return string Normalized header name
194+ */
195+ protected function normalizeHeaderName ($ name ): string
196+ {
197+ try {
198+ $ name = str_replace (["\r" , "\n" , "\t" ], '' , trim ($ name ));
199+ } catch (Throwable $ e ) {
200+ throw new InvalidArgumentException (
201+ sprintf ('Header name must be a string, %s given ' , gettype ($ name )), StatusCode::BAD_REQUEST
202+ );
203+ }
204+
205+ if ('' === $ name ) {
206+ throw new InvalidArgumentException ('Empty header name ' , StatusCode::BAD_REQUEST );
207+ }
208+
209+ return $ name ;
210+ }
211+
212+ /**
213+ * @param string $name
214+ * @param string|string[] $value
215+ *
216+ * @return array
217+ */
218+ protected function normalizeHeaderValue (string $ name , $ value ): array
219+ {
220+ $ type = gettype ($ value );
221+ switch ($ type ) {
222+ case 'array ' :
223+ case 'integer ' :
224+ case 'double ' :
225+ case 'string ' :
226+ $ value = (array )$ value ;
227+ break ;
228+ default :
229+ throw new InvalidArgumentException (
230+ sprintf ('Invalid header value, expects string or array, "%s" given ' , $ type ), StatusCode::BAD_REQUEST
231+ );
232+ }
233+
234+ if (empty ($ value = array_map (function ($ v ) {
235+ return trim (preg_replace ('/\s+/ ' , ' ' , $ v ));
236+ }, $ value ))) {
237+ throw new InvalidArgumentException (
238+ sprintf ('The value for header "%s" cannot be empty ' , $ name ), StatusCode::BAD_REQUEST
239+ );
240+ }
241+
242+ return $ value ;
243+ }
183244}
0 commit comments