@@ -157,17 +157,22 @@ private function setHeaders(array $headers)
157
157
}
158
158
}
159
159
160
+ /**
161
+ * @param mixed $value
162
+ *
163
+ * @return string[]
164
+ */
160
165
private function normalizeHeaderValue ($ value )
161
166
{
162
167
if (!is_array ($ value )) {
163
- return $ this ->trimHeaderValues ([$ value ]);
168
+ return $ this ->trimAndValidateHeaderValues ([$ value ]);
164
169
}
165
170
166
171
if (count ($ value ) === 0 ) {
167
172
throw new \InvalidArgumentException ('Header value can not be an empty array. ' );
168
173
}
169
174
170
- return $ this ->trimHeaderValues ($ value );
175
+ return $ this ->trimAndValidateHeaderValues ($ value );
171
176
}
172
177
173
178
/**
@@ -178,13 +183,13 @@ private function normalizeHeaderValue($value)
178
183
* header-field = field-name ":" OWS field-value OWS
179
184
* OWS = *( SP / HTAB )
180
185
*
181
- * @param string [] $values Header values
186
+ * @param mixed [] $values Header values
182
187
*
183
188
* @return string[] Trimmed header values
184
189
*
185
190
* @see https://tools.ietf.org/html/rfc7230#section-3.2.4
186
191
*/
187
- private function trimHeaderValues (array $ values )
192
+ private function trimAndValidateHeaderValues (array $ values )
188
193
{
189
194
return array_map (function ($ value ) {
190
195
if (!is_scalar ($ value ) && null !== $ value ) {
@@ -194,10 +199,20 @@ private function trimHeaderValues(array $values)
194
199
));
195
200
}
196
201
197
- return trim ((string ) $ value , " \t" );
202
+ $ trimmed = trim ((string ) $ value , " \t" );
203
+ $ this ->assertValue ($ trimmed );
204
+
205
+ return $ trimmed ;
198
206
}, array_values ($ values ));
199
207
}
200
208
209
+ /**
210
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2
211
+ *
212
+ * @param mixed $header
213
+ *
214
+ * @return void
215
+ */
201
216
private function assertHeader ($ header )
202
217
{
203
218
if (!is_string ($ header )) {
@@ -210,5 +225,46 @@ private function assertHeader($header)
210
225
if ($ header === '' ) {
211
226
throw new \InvalidArgumentException ('Header name can not be empty. ' );
212
227
}
228
+
229
+ if (! preg_match ('/^[a-zA-Z0-9 \'`#$%&*+.^_|~!-]+$/ ' , $ header )) {
230
+ throw new \InvalidArgumentException (
231
+ sprintf (
232
+ '"%s" is not valid header name ' ,
233
+ $ header
234
+ )
235
+ );
236
+ }
237
+ }
238
+
239
+ /**
240
+ * @param string $value
241
+ *
242
+ * @return void
243
+ *
244
+ * @see https://tools.ietf.org/html/rfc7230#section-3.2
245
+ *
246
+ * field-value = *( field-content / obs-fold )
247
+ * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
248
+ * field-vchar = VCHAR / obs-text
249
+ * VCHAR = %x21-7E
250
+ * obs-text = %x80-FF
251
+ * obs-fold = CRLF 1*( SP / HTAB )
252
+ */
253
+ private function assertValue ($ value )
254
+ {
255
+ // The regular expression intentionally does not support the obs-fold production, because as
256
+ // per RFC 7230#3.2.4:
257
+ //
258
+ // A sender MUST NOT generate a message that includes
259
+ // line folding (i.e., that has any field-value that contains a match to
260
+ // the obs-fold rule) unless the message is intended for packaging
261
+ // within the message/http media type.
262
+ //
263
+ // Clients must not send a request with line folding and a server sending folded headers is
264
+ // likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
265
+ // folding is not likely to break any legitimate use case.
266
+ if (! preg_match ('/^(?:[\x21-\x7E\x80-\xFF](?:[\x20\x09]+[\x21-\x7E\x80-\xFF])?)*$/ ' , $ value )) {
267
+ throw new \InvalidArgumentException (sprintf ('"%s" is not valid header value ' , $ value ));
268
+ }
213
269
}
214
270
}
0 commit comments