Thanks to visit codestin.com
Credit goes to github.com

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

Commit 9775572

Browse files
committed
Based on new tests and links to relevant specifications, the code from zendframework/zendframework#5608 was invalid; header lines may never start with whitespace. This patch reverts that code, and updates the `fromString()` logic to capture whitespace on subsequent lines to include in the multi-line header value. Tests have been updated where necessary to use a regex for testing the existence of whitespace between multiline values.
1 parent 4812ec5 commit 9775572

4 files changed

Lines changed: 12 additions & 76 deletions

File tree

src/Headers.php

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public static function fromString($string)
5858
foreach (explode("\r\n", $string) as $line) {
5959

6060
// check if a header name is present
61-
if (preg_match('/^\s*(?P<name>[^()><@,;:\"\\/\[\]?=}{ \t]+):.*$/', $line, $matches)) {
61+
if (preg_match('/^(?P<name>[^()><@,;:\"\\/\[\]?=}{ \t]+):.*$/', $line, $matches)) {
6262
if ($current) {
6363
// a header name was present, then store the current complete line
6464
$headers->headersKeys[] = static::createKey($current['name']);
@@ -68,17 +68,9 @@ public static function fromString($string)
6868
'name' => $matches['name'],
6969
'line' => trim($line)
7070
);
71-
} elseif (preg_match('/^\s+.*$/', $line, $matches)) {
72-
if ($current) {
73-
// continuation: append to current line
74-
$current['line'] .= trim($line);
75-
} else {
76-
// Line does not match header format!
77-
throw new Exception\RuntimeException(sprintf(
78-
'Line "%s" does not match header format!',
79-
$line
80-
));
81-
}
71+
} elseif (preg_match('/^(?P<ws>\s+).*$/', $line, $matches)) {
72+
// continuation: append to current line
73+
$current['line'] .= "\r\n" . $matches['ws'] . trim($line);
8274
} elseif (preg_match('/^\s*$/', $line)) {
8375
// empty line indicates end of headers
8476
break;

test/HeadersTest.php

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,6 @@ public function testHeadersFromStringFactoryCreatesSingleObject()
3838
$this->assertEquals('foo-bar', $header->getFieldValue());
3939
}
4040

41-
public function testHeadersFromStringFactoryCreateSingleObjectWithLeadingWhitespaces()
42-
{
43-
$headers = Headers::fromString(" Fake: foo-bar");
44-
$this->assertEquals(1, $headers->count());
45-
46-
$header = $headers->get('fake');
47-
$this->assertInstanceOf('Zend\Http\Header\GenericHeader', $header);
48-
$this->assertEquals('Fake', $header->getFieldName());
49-
$this->assertEquals('foo-bar', $header->getFieldValue());
50-
}
51-
5241
public function testHeadersFromStringFactoryCreatesSingleObjectWithContinuationLine()
5342
{
5443
$headers = Headers::fromString("Fake: foo-bar,\r\n blah-blah");
@@ -58,19 +47,7 @@ public function testHeadersFromStringFactoryCreatesSingleObjectWithContinuationL
5847
$this->assertInstanceOf('Zend\Http\Header\GenericHeader', $header);
5948
$this->assertEquals('Fake', $header->getFieldName());
6049
// any leading space MAY be replaced by a single space @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
61-
$this->assertEquals('foo-bar, blah-blah', $header->getFieldValue());
62-
}
63-
64-
public function testHeadersFromStringFactoryCreatesSingleObjectWithContinuationLineAndLeadingWhitespaces()
65-
{
66-
$headers = Headers::fromString(" Fake: foo-bar,\r\n blah-blah");
67-
$this->assertEquals(1, $headers->count());
68-
69-
$header = $headers->get('fake');
70-
$this->assertInstanceOf('Zend\Http\Header\GenericHeader', $header);
71-
$this->assertEquals('Fake', $header->getFieldName());
72-
// any leading space MAY be replaced by a single space @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html
73-
$this->assertEquals('foo-bar, blah-blah', $header->getFieldValue());
50+
$this->assertRegexp("#foo-bar,\r\n\s+blah-blah#", $header->getFieldValue());
7451
}
7552

7653
public function testHeadersFromStringFactoryCreatesSingleObjectWithHeaderBreakLine()
@@ -84,17 +61,6 @@ public function testHeadersFromStringFactoryCreatesSingleObjectWithHeaderBreakLi
8461
$this->assertEquals('foo-bar', $header->getFieldValue());
8562
}
8663

87-
public function testHeadersFromStringFactoryCreatesSingleObjectWithHeaderBreakLineAndLeadingWhitespaces()
88-
{
89-
$headers = Headers::fromString(" Fake: foo-bar\r\n\r\n");
90-
$this->assertEquals(1, $headers->count());
91-
92-
$header = $headers->get('fake');
93-
$this->assertInstanceOf('Zend\Http\Header\GenericHeader', $header);
94-
$this->assertEquals('Fake', $header->getFieldName());
95-
$this->assertEquals('foo-bar', $header->getFieldValue());
96-
}
97-
9864
public function testHeadersFromStringFactoryRespectsSpecAllowedMultiLineHeaders()
9965
{
10066
$headers = Headers::fromString("Foo: foo-bar\r\nX-Another: another\r\n X-Actually-A-Continuation:ofSomeKindOfValue\r\nX-Another: another\r\n");
@@ -103,7 +69,7 @@ public function testHeadersFromStringFactoryRespectsSpecAllowedMultiLineHeaders(
10369
// check continued header
10470
$header = $headers->get('X-Another');
10571
$this->assertEquals('X-Another', $header->getFieldName());
106-
$this->assertEquals('another X-Actually-A-Continuation:ofSomeKindOfValue', $header->getFieldValue());
72+
$this->assertRegexp("#another\r\n\s+X-Actually-A-Continuation:ofSomeKindOfValue#", $header->getFieldValue());
10773
}
10874

10975
public function testHeadersFromStringFactoryThrowsExceptionOnMalformedHeaderLine()
@@ -112,12 +78,6 @@ public function testHeadersFromStringFactoryThrowsExceptionOnMalformedHeaderLine
11278
Headers::fromString("Fake = foo-bar\r\n\r\n");
11379
}
11480

115-
public function testHeadersFromStringFactoryThrowsExceptionOnMalformedHeaderLineAndLeadingWhitespaces()
116-
{
117-
$this->setExpectedException('Zend\Http\Exception\RuntimeException', 'does not match');
118-
Headers::fromString(" Fake = foo-bar\r\n\r\n");
119-
}
120-
12181
public function testHeadersFromStringFactoryCreatesMultipleObjects()
12282
{
12383
$headers = Headers::fromString("Fake: foo-bar\r\nAnother-Fake: boo-baz");
@@ -134,22 +94,6 @@ public function testHeadersFromStringFactoryCreatesMultipleObjects()
13494
$this->assertEquals('boo-baz', $header->getFieldValue());
13595
}
13696

137-
public function testHeadersFromStringFactoryCreatesMultipleObjectsWithLeadingWhitespaces()
138-
{
139-
$headers = Headers::fromString(" Fake: foo-bar\r\nAnother-Fake: boo-baz");
140-
$this->assertEquals(2, $headers->count());
141-
142-
$header = $headers->get('fake');
143-
$this->assertInstanceOf('Zend\Http\Header\GenericHeader', $header);
144-
$this->assertEquals('Fake', $header->getFieldName());
145-
$this->assertEquals('foo-bar', $header->getFieldValue());
146-
147-
$header = $headers->get('anotherfake');
148-
$this->assertInstanceOf('Zend\Http\Header\GenericHeader', $header);
149-
$this->assertEquals('Another-Fake', $header->getFieldName());
150-
$this->assertEquals('boo-baz', $header->getFieldValue());
151-
}
152-
15397
public function testHeadersFromStringMultiHeaderWillAggregateLazyLoadedHeaders()
15498
{
15599
$headers = new Headers();

test/Response/ResponseStreamTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ public function testMultilineHeader()
7575
$this->assertEquals(6, count($response->getHeaders()), 'Header count is expected to be 6');
7676

7777
// Check header integrity
78-
$this->assertEquals('timeout=15,max=100', $response->getHeaders()->get('keep-alive')->getFieldValue());
79-
$this->assertEquals('text/html;charset=iso-8859-1', $response->getHeaders()->get('content-type')->getFieldValue());
78+
$this->assertRegexp("#timeout=15,\r\n\s+max=100#", $response->getHeaders()->get('keep-alive')->getFieldValue());
79+
$this->assertRegexp("#text/html;\r\n\s+charset=iso-8859-1#", $response->getHeaders()->get('content-type')->getFieldValue());
8080
}
8181

8282

test/ResponseTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,8 @@ public function testMultilineHeaderNoSpaces()
327327
$this->assertEquals(6, count($response->getHeaders()), 'Header count is expected to be 6');
328328

329329
// Check header integrity
330-
$this->assertEquals('timeout=15,max=100', $response->getHeaders()->get('keep-alive')->getFieldValue());
331-
$this->assertEquals('text/html;charset=iso-8859-1', $response->getHeaders()->get('content-type')->getFieldValue());
330+
$this->assertRegexp("#timeout=15,\r\n\s+max=100#", $response->getHeaders()->get('keep-alive')->getFieldValue());
331+
$this->assertRegexp("#text/html;\r\n\s+charset=iso-8859-1#", $response->getHeaders()->get('content-type')->getFieldValue());
332332
}
333333

334334
public function testMultilineHeader()
@@ -339,8 +339,8 @@ public function testMultilineHeader()
339339
$this->assertEquals(6, count($response->getHeaders()), 'Header count is expected to be 6');
340340

341341
// Check header integrity
342-
$this->assertEquals('timeout=15,max=100', $response->getHeaders()->get('keep-alive')->getFieldValue());
343-
$this->assertEquals('text/html;charset=iso-8859-1', $response->getHeaders()->get('content-type')->getFieldValue());
342+
$this->assertRegexp("#timeout=15,\r\n\s+max=100#", $response->getHeaders()->get('keep-alive')->getFieldValue());
343+
$this->assertRegexp("#text/html;\r\n\s+charset=iso-8859-1#", $response->getHeaders()->get('content-type')->getFieldValue());
344344
}
345345

346346
/**

0 commit comments

Comments
 (0)