File tree Expand file tree Collapse file tree 5 files changed +73
-3
lines changed Expand file tree Collapse file tree 5 files changed +73
-3
lines changed Original file line number Diff line number Diff line change @@ -95,7 +95,7 @@ protected static function splitStream(StreamInterface $stream) : array
95
95
if (! isset ($ headers [$ currentHeader ])) {
96
96
$ headers [$ currentHeader ] = [];
97
97
}
98
- $ headers [$ currentHeader ][] = ltrim ($ matches ['value ' ]);
98
+ $ headers [$ currentHeader ][] = trim ($ matches ['value ' ], "\t " );
99
99
continue ;
100
100
}
101
101
@@ -109,7 +109,7 @@ protected static function splitStream(StreamInterface $stream) : array
109
109
110
110
// Append continuation to last header value found
111
111
$ value = array_pop ($ headers [$ currentHeader ]);
112
- $ headers [$ currentHeader ][] = $ value . ' ' . ltrim ($ line );
112
+ $ headers [$ currentHeader ][] = $ value . ' ' . trim ($ line, "\t " );
113
113
}
114
114
115
115
// use RelativeStream to avoid copying initial stream into memory
Original file line number Diff line number Diff line change @@ -398,7 +398,8 @@ private function filterHeaderValue($values) : array
398
398
return array_map (function ($ value ) {
399
399
HeaderSecurity::assertValid ($ value );
400
400
401
- return (string ) $ value ;
401
+ // Remove optional whitespace (OWS, RFC 7230#3.2.3) around the header value.
402
+ return trim ((string ) $ value , "\t " );
402
403
}, array_values ($ values ));
403
404
}
404
405
Original file line number Diff line number Diff line change @@ -336,6 +336,27 @@ public function testWithAddedHeaderAllowsHeaderContinuations(): void
336
336
$ this ->assertSame ("value, \r\n second value " , $ message ->getHeaderLine ('X-Foo-Bar ' ));
337
337
}
338
338
339
+ /** @return non-empty-array<non-empty-string, array{non-empty-string}> */
340
+ public function headersWithWhitespace (): array
341
+ {
342
+ return [
343
+ 'no ' => ["Baz " ],
344
+ 'leading ' => [" Baz " ],
345
+ 'trailing ' => ["Baz " ],
346
+ 'both ' => [" Baz " ],
347
+ 'mixed ' => [" \t Baz \t \t" ],
348
+ ];
349
+ }
350
+
351
+ /**
352
+ * @dataProvider headersWithWhitespace
353
+ */
354
+ public function testWithHeaderTrimsWhitespace (string $ value ): void
355
+ {
356
+ $ message = $ this ->message ->withHeader ('X-Foo-Bar ' , $ value );
357
+ $ this ->assertSame (trim ($ value , "\t " ), $ message ->getHeaderLine ('X-Foo-Bar ' ));
358
+ }
359
+
339
360
/** @return non-empty-array<non-empty-string, array{int|float}> */
340
361
public function numericHeaderValuesProvider (): array
341
362
{
Original file line number Diff line number Diff line change @@ -247,6 +247,30 @@ public function testCanDeserializeResponseWithHeaderContinuations($text) : void
247
247
$ this ->assertSame ('Baz; Bat ' , $ request ->getHeaderLine ('X-Foo-Bar ' ));
248
248
}
249
249
250
+ /** @return non-empty-array<non-empty-string, array{non-empty-string}> */
251
+ public function headersWithWhitespace (): array
252
+ {
253
+ return [
254
+ 'no ' => ["POST /foo HTTP/1.0 \r\nContent-Type: text/plain \r\nX-Foo-Bar:Baz \r\n\r\nContent! " ],
255
+ 'leading ' => ["POST /foo HTTP/1.0 \r\nContent-Type: text/plain \r\nX-Foo-Bar: Baz \r\n\r\nContent! " ],
256
+ 'trailing ' => ["POST /foo HTTP/1.0 \r\nContent-Type: text/plain \r\nX-Foo-Bar:Baz \r\n\r\nContent! " ],
257
+ 'both ' => ["POST /foo HTTP/1.0 \r\nContent-Type: text/plain \r\nX-Foo-Bar: Baz \r\n\r\nContent! " ],
258
+ 'mixed ' => ["POST /foo HTTP/1.0 \r\nContent-Type: text/plain \r\nX-Foo-Bar: \t Baz \t \t\r\n\r\nContent! " ],
259
+ ];
260
+ }
261
+
262
+ /**
263
+ * @dataProvider headersWithWhitespace
264
+ */
265
+ public function testDeserializationRemovesWhitespaceAroundValues (string $ text ): void
266
+ {
267
+ $ request = Serializer::fromString ($ text );
268
+
269
+ $ this ->assertInstanceOf (Request::class, $ request );
270
+
271
+ $ this ->assertSame ('Baz ' , $ request ->getHeaderLine ('X-Foo-Bar ' ));
272
+ }
273
+
250
274
public function messagesWithInvalidHeaders () : array
251
275
{
252
276
return [
Original file line number Diff line number Diff line change @@ -121,6 +121,30 @@ public function testCanDeserializeResponseWithHeaderContinuations($text)
121
121
$ this ->assertSame ('Baz; Bat ' , $ response ->getHeaderLine ('X-Foo-Bar ' ));
122
122
}
123
123
124
+ /** @return non-empty-array<non-empty-string, array{non-empty-string}> */
125
+ public function headersWithWhitespace (): array
126
+ {
127
+ return [
128
+ 'no ' => ["HTTP/1.0 200 A-OK \r\nContent-Type: text/plain \r\nX-Foo-Bar:Baz \r\n\r\nContent! " ],
129
+ 'leading ' => ["HTTP/1.0 200 A-OK \r\nContent-Type: text/plain \r\nX-Foo-Bar: Baz \r\n\r\nContent! " ],
130
+ 'trailing ' => ["HTTP/1.0 200 A-OK \r\nContent-Type: text/plain \r\nX-Foo-Bar:Baz \r\n\r\nContent! " ],
131
+ 'both ' => ["HTTP/1.0 200 A-OK \r\nContent-Type: text/plain \r\nX-Foo-Bar: Baz \r\n\r\nContent! " ],
132
+ 'mixed ' => ["HTTP/1.0 200 A-OK \r\nContent-Type: text/plain \r\nX-Foo-Bar: \t Baz \t \t\r\n\r\nContent! " ],
133
+ ];
134
+ }
135
+
136
+ /**
137
+ * @dataProvider headersWithWhitespace
138
+ */
139
+ public function testDeserializationRemovesWhitespaceAroundValues (string $ text ): void
140
+ {
141
+ $ response = Serializer::fromString ($ text );
142
+
143
+ $ this ->assertInstanceOf (Response::class, $ response );
144
+
145
+ $ this ->assertSame ('Baz ' , $ response ->getHeaderLine ('X-Foo-Bar ' ));
146
+ }
147
+
124
148
public function testCanDeserializeResponseWithoutBody ()
125
149
{
126
150
$ text = "HTTP/1.0 204 \r\nX-Foo-Bar: Baz " ;
You can’t perform that action at this time.
0 commit comments