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

Commit 74d36ca

Browse files
committed
Merge branch 'hotfix/190' into develop
Forward port #190
2 parents 7a3b70e + 5469925 commit 74d36ca

File tree

4 files changed

+67
-2
lines changed

4 files changed

+67
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ All notable changes to this project will be documented in this file, in reverse
3232

3333
### Changed
3434

35-
- Nothing.
35+
- [#190](https://github.com/zendframework/zend-http/pull/190) changes `ContentSecurityPolicy` to allow multiple values. Before it was not possible to provide multiple headers of that type.
3636

3737
### Deprecated
3838

src/Header/ContentSecurityPolicy.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
* @link http://www.w3.org/TR/CSP/
1414
*/
15-
class ContentSecurityPolicy implements HeaderInterface
15+
class ContentSecurityPolicy implements MultipleHeaderInterface
1616
{
1717
/**
1818
* Valid directive names
@@ -154,4 +154,20 @@ public function toString()
154154
{
155155
return sprintf('%s: %s', $this->getFieldName(), $this->getFieldValue());
156156
}
157+
158+
public function toStringMultipleHeaders(array $headers)
159+
{
160+
$strings = [$this->toString()];
161+
foreach ($headers as $header) {
162+
if (! $header instanceof ContentSecurityPolicy) {
163+
throw new Exception\RuntimeException(
164+
'The ContentSecurityPolicy multiple header implementation can only'
165+
. ' accept an array of ContentSecurityPolicy headers'
166+
);
167+
}
168+
$strings[] = $header->toString();
169+
}
170+
171+
return implode("\r\n", $strings) . "\r\n";
172+
}
157173
}

src/HeaderLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class HeaderLoader extends PluginClassLoader
3636
'contentlocation' => Header\ContentLocation::class,
3737
'contentmd5' => Header\ContentMD5::class,
3838
'contentrange' => Header\ContentRange::class,
39+
'contentsecuritypolicy' => Header\ContentSecurityPolicy::class,
3940
'contenttransferencoding' => Header\ContentTransferEncoding::class,
4041
'contenttype' => Header\ContentType::class,
4142
'cookie' => Header\Cookie::class,

test/Header/ContentSecurityPolicyTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@
88
namespace ZendTest\Http\Header;
99

1010
use PHPUnit\Framework\TestCase;
11+
use Zend\Http\Exception\RuntimeException;
1112
use Zend\Http\Header\ContentSecurityPolicy;
1213
use Zend\Http\Header\Exception\InvalidArgumentException;
14+
use Zend\Http\Header\GenericHeader;
1315
use Zend\Http\Header\HeaderInterface;
16+
use Zend\Http\Header\MultipleHeaderInterface;
17+
use Zend\Http\Headers;
1418

1519
class ContentSecurityPolicyTest extends TestCase
1620
{
@@ -25,6 +29,7 @@ public function testContentSecurityPolicyFromStringParsesDirectivesCorrectly()
2529
$csp = ContentSecurityPolicy::fromString(
2630
"Content-Security-Policy: default-src 'none'; script-src 'self'; img-src 'self'; style-src 'self';"
2731
);
32+
$this->assertInstanceOf(MultipleHeaderInterface::class, $csp);
2833
$this->assertInstanceOf(HeaderInterface::class, $csp);
2934
$this->assertInstanceOf(ContentSecurityPolicy::class, $csp);
3035
$directives = [
@@ -139,4 +144,47 @@ public function testContentSecurityPolicySetDirectiveWithEmptyReportUriRemovesEx
139144
$csp->toString()
140145
);
141146
}
147+
148+
public function testToStringMultipleHeaders()
149+
{
150+
$csp = new ContentSecurityPolicy();
151+
$csp->setDirective('default-src', ["'self'"]);
152+
153+
$additional = new ContentSecurityPolicy();
154+
$additional->setDirective('img-src', ['https://*.github.com']);
155+
156+
self::assertSame(
157+
"Content-Security-Policy: default-src 'self';\r\n"
158+
. "Content-Security-Policy: img-src https://*.github.com;\r\n",
159+
$csp->toStringMultipleHeaders([$additional])
160+
);
161+
}
162+
163+
public function testToStringMultipleHeadersExceptionIfDifferent()
164+
{
165+
$csp = new ContentSecurityPolicy();
166+
$csp->setDirective('default-src', ["'self'"]);
167+
168+
$additional = new GenericHeader();
169+
170+
$this->expectException(RuntimeException::class);
171+
$this->expectExceptionMessage(
172+
'The ContentSecurityPolicy multiple header implementation'
173+
. ' can only accept an array of ContentSecurityPolicy headers'
174+
);
175+
$csp->toStringMultipleHeaders([$additional]);
176+
}
177+
178+
public function testMultiple()
179+
{
180+
$headers = new Headers();
181+
$headers->addHeader((new ContentSecurityPolicy())->setDirective('default-src', ["'self'"]));
182+
$headers->addHeader((new ContentSecurityPolicy())->setDirective('img-src', ['https://*.github.com']));
183+
184+
self::assertSame(
185+
"Content-Security-Policy: default-src 'self';\r\n"
186+
. "Content-Security-Policy: img-src https://*.github.com;\r\n",
187+
$headers->toString()
188+
);
189+
}
142190
}

0 commit comments

Comments
 (0)