Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 13a4626

Browse files
committed
Merge branch 'hotfix/99'
Close #99
2 parents b4fe59a + 147613a commit 13a4626

File tree

5 files changed

+148
-35
lines changed

5 files changed

+148
-35
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ All notable changes to this project will be documented in this file, in reverse
2424
in the cloned instance.
2525
- [#103](https://github.com/zendframework/zend-diactoros/pull/103) fixes the
2626
constructor of `Response` to ensure that null status codes are not possible.
27+
- [#99](https://github.com/zendframework/zend-diactoros/pull/99) fixes
28+
validation of header values submitted via request and response constructors as
29+
follows:
30+
- numeric (integer and float) values are now properly allowed (this solves
31+
some reported issues with setting Content-Length headers)
32+
- invalid header names (non-string values or empty strings) now raise an
33+
exception.
34+
- invalid individual header values (non-string, non-numeric) now raise an
35+
exception.
2736

2837
## 1.2.0 - 2015-11-24
2938

src/MessageTrait.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,11 +337,28 @@ private function filterHeaders(array $originalHeaders)
337337
$headerNames = $headers = [];
338338
foreach ($originalHeaders as $header => $value) {
339339
if (! is_string($header)) {
340-
continue;
340+
throw new InvalidArgumentException(sprintf(
341+
'Invalid header name; expected non-empty string, received %s',
342+
gettype($header)
343+
));
341344
}
342345

343-
if (! is_array($value) && ! is_string($value)) {
344-
continue;
346+
if (! is_array($value) && ! is_string($value) && ! is_numeric($value)) {
347+
throw new InvalidArgumentException(sprintf(
348+
'Invalid header value type; expected number, string, or array; received %s',
349+
(is_object($value) ? get_class($value) : gettype($value))
350+
));
351+
}
352+
353+
if (is_array($value)) {
354+
array_walk($value, function ($item) {
355+
if (! is_string($item) && ! is_numeric($item)) {
356+
throw new InvalidArgumentException(sprintf(
357+
'Invalid header value type; expected number, string, or array; received %s',
358+
(is_object($item) ? get_class($item) : gettype($item))
359+
));
360+
}
361+
});
345362
}
346363

347364
if (! is_array($value)) {

test/MessageTraitTest.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010
namespace ZendTest\Diactoros;
1111

12+
use InvalidArgumentException;
1213
use PHPUnit_Framework_TestCase as TestCase;
1314
use Psr\Http\Message\MessageInterface;
15+
use ReflectionMethod;
1416
use Zend\Diactoros\Request;
1517

1618
class MessageTraitTest extends TestCase
@@ -266,4 +268,84 @@ public function testWithAddedHeaderAllowsHeaderContinuations()
266268
$message = $this->message->withAddedHeader('X-Foo-Bar', "value,\r\n second value");
267269
$this->assertEquals("value,\r\n second value", $message->getHeaderLine('X-Foo-Bar'));
268270
}
271+
272+
public function testNumericHeaderValues()
273+
{
274+
return [
275+
'integer' => [ 123 ],
276+
'float' => [ 12.3 ],
277+
];
278+
}
279+
280+
/**
281+
* @dataProvider testNumericHeaderValues
282+
* @group 99
283+
*/
284+
public function testFilterHeadersShouldAllowIntegersAndFloats($value)
285+
{
286+
$filter = new ReflectionMethod($this->message, 'filterHeaders');
287+
$filter->setAccessible(true);
288+
$headers = [
289+
'X-Test-Array' => [ $value ],
290+
'X-Test-Scalar' => $value,
291+
];
292+
$test = $filter->invoke($this->message, $headers);
293+
$this->assertEquals([
294+
[
295+
'x-test-array' => 'X-Test-Array',
296+
'x-test-scalar' => 'X-Test-Scalar',
297+
],
298+
[
299+
'X-Test-Array' => [ $value ],
300+
'X-Test-Scalar' => [ $value ],
301+
]
302+
], $test);
303+
}
304+
305+
public function invalidHeaderValueTypes()
306+
{
307+
return [
308+
'null' => [null],
309+
'true' => [true],
310+
'false' => [false],
311+
'object' => [(object) ['header' => ['foo', 'bar']]],
312+
];
313+
}
314+
315+
public function invalidArrayHeaderValues()
316+
{
317+
$values = $this->invalidHeaderValueTypes();
318+
$values['array'] = [['INVALID']];
319+
return $values;
320+
}
321+
322+
/**
323+
* @dataProvider invalidArrayHeaderValues
324+
* @group 99
325+
*/
326+
public function testFilterHeadersShouldRaiseExceptionForInvalidHeaderValuesInArrays($value)
327+
{
328+
$filter = new ReflectionMethod($this->message, 'filterHeaders');
329+
$filter->setAccessible(true);
330+
$headers = [
331+
'X-Test-Array' => [ $value ],
332+
];
333+
$this->setExpectedException('InvalidArgumentException', 'header value type');
334+
$filter->invoke($this->message, $headers);
335+
}
336+
337+
/**
338+
* @dataProvider invalidHeaderValueTypes
339+
* @group 99
340+
*/
341+
public function testFilterHeadersShouldRaiseExceptionForInvalidHeaderScalarValues($value)
342+
{
343+
$filter = new ReflectionMethod($this->message, 'filterHeaders');
344+
$filter->setAccessible(true);
345+
$headers = [
346+
'X-Test-Scalar' => $value,
347+
];
348+
$this->setExpectedException('InvalidArgumentException', 'header value type');
349+
$filter->invoke($this->message, $headers);
350+
}
269351
}

test/RequestTest.php

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace ZendTest\Diactoros;
1111

12+
use InvalidArgumentException;
1213
use PHPUnit_Framework_TestCase as TestCase;
1314
use Zend\Diactoros\Request;
1415
use Zend\Diactoros\Stream;
@@ -192,24 +193,25 @@ public function testConstructorRaisesExceptionForInvalidBody($body)
192193
new Request(null, null, $body);
193194
}
194195

195-
public function testConstructorIgonoresInvalidHeaders()
196+
public function invalidHeaderTypes()
196197
{
197-
$headers = [
198-
[ 'INVALID' ],
199-
'x-invalid-null' => null,
200-
'x-invalid-true' => true,
201-
'x-invalid-false' => false,
202-
'x-invalid-int' => 1,
203-
'x-invalid-object' => (object) ['INVALID'],
204-
'x-valid-string' => 'VALID',
205-
'x-valid-array' => [ 'VALID' ],
206-
];
207-
$expected = [
208-
'x-valid-string' => [ 'VALID' ],
209-
'x-valid-array' => [ 'VALID' ],
198+
return [
199+
'indexed-array' => [[['INVALID']], 'header name'],
200+
'null' => [['x-invalid-null' => null]],
201+
'true' => [['x-invalid-true' => true]],
202+
'false' => [['x-invalid-false' => false]],
203+
'object' => [['x-invalid-object' => (object) ['INVALID']]],
210204
];
211-
$request = new Request(null, null, 'php://memory', $headers);
212-
$this->assertEquals($expected, $request->getHeaders());
205+
}
206+
207+
/**
208+
* @dataProvider invalidHeaderTypes
209+
* @group 99
210+
*/
211+
public function testConstructorRaisesExceptionForInvalidHeaders($headers, $contains = 'header value type')
212+
{
213+
$this->setExpectedException('InvalidArgumentException', $contains);
214+
new Request(null, null, 'php://memory', $headers);
213215
}
214216

215217
public function testRequestTargetIsSlashWhenNoUriPresent()

test/ResponseTest.php

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace ZendTest\Diactoros;
1111

12+
use InvalidArgumentException;
1213
use PHPUnit_Framework_TestCase as TestCase;
1314
use Zend\Diactoros\Response;
1415
use Zend\Diactoros\Stream;
@@ -135,24 +136,26 @@ public function testConstructorRaisesExceptionForInvalidBody($body)
135136
new Response($body);
136137
}
137138

138-
public function testConstructorIgonoresInvalidHeaders()
139+
140+
public function invalidHeaderTypes()
139141
{
140-
$headers = [
141-
[ 'INVALID' ],
142-
'x-invalid-null' => null,
143-
'x-invalid-true' => true,
144-
'x-invalid-false' => false,
145-
'x-invalid-int' => 1,
146-
'x-invalid-object' => (object) ['INVALID'],
147-
'x-valid-string' => 'VALID',
148-
'x-valid-array' => [ 'VALID' ],
149-
];
150-
$expected = [
151-
'x-valid-string' => [ 'VALID' ],
152-
'x-valid-array' => [ 'VALID' ],
142+
return [
143+
'indexed-array' => [[['INVALID']], 'header name'],
144+
'null' => [['x-invalid-null' => null]],
145+
'true' => [['x-invalid-true' => true]],
146+
'false' => [['x-invalid-false' => false]],
147+
'object' => [['x-invalid-object' => (object) ['INVALID']]],
153148
];
154-
$response = new Response('php://memory', 200, $headers);
155-
$this->assertEquals($expected, $response->getHeaders());
149+
}
150+
151+
/**
152+
* @dataProvider invalidHeaderTypes
153+
* @group 99
154+
*/
155+
public function testConstructorRaisesExceptionForInvalidHeaders($headers, $contains = 'header value type')
156+
{
157+
$this->setExpectedException('InvalidArgumentException', $contains);
158+
new Response('php://memory', 200, $headers);
156159
}
157160

158161
public function testInvalidStatusCodeInConstructor()

0 commit comments

Comments
 (0)