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

Commit 1401582

Browse files
committed
Merge branch 'hotfix/41'
Close #41 Fixes #40
2 parents 189b660 + 9575fd4 commit 1401582

4 files changed

+58
-10
lines changed

CHANGELOG.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file, in reverse
44

55
Versions 0.3.0 and prior were released as "weierophinney/problem-details".
66

7-
## 1.0.1 - TBD
7+
## 1.0.1 - 2018-07-25
88

99
### Added
1010

@@ -24,8 +24,11 @@ Versions 0.3.0 and prior were released as "weierophinney/problem-details".
2424

2525
### Fixed
2626

27-
- [#39](https://github.com/zendframework/zend-problem-details/pull/39)
28-
adds the `public` visibility modifier to all constants.
27+
- [#39](https://github.com/zendframework/zend-problem-details/pull/39) adds the `public` visibility modifier to all constants.
28+
29+
- [#41](https://github.com/zendframework/zend-problem-details/pull/41) prevents crashes when the `ProblemDetailsResponseFactory` attempts to
30+
encode malformed UTF-8 sequences to JSON by ensuring the
31+
`JSON_PARTIAL_OUTPUT_ON_ERROR` flag is enabled.
2932

3033
## 1.0.0 - 2018-03-15
3134

src/ProblemDetailsResponseFactory.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
use function sprintf;
3232
use function strpos;
3333

34+
use const JSON_PARTIAL_OUTPUT_ON_ERROR;
3435
use const JSON_PRESERVE_ZERO_FRACTION;
3536
use const JSON_PRETTY_PRINT;
3637
use const JSON_UNESCAPED_SLASHES;
@@ -166,8 +167,11 @@ class ProblemDetailsResponseFactory
166167
*
167168
* On non-debug mode:
168169
* defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION
170+
* | JSON_PARTIAL_OUTPUT_ON_ERROR
171+
*
169172
* On debug mode:
170173
* defaults to JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION
174+
* | JSON_PARTIAL_OUTPUT_ON_ERROR
171175
*
172176
* @var int
173177
*/
@@ -213,7 +217,10 @@ public function __construct(
213217
};
214218
$this->isDebug = $isDebug;
215219
if (! $jsonFlags) {
216-
$jsonFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION;
220+
$jsonFlags = JSON_UNESCAPED_SLASHES
221+
| JSON_UNESCAPED_UNICODE
222+
| JSON_PRESERVE_ZERO_FRACTION
223+
| JSON_PARTIAL_OUTPUT_ON_ERROR;
217224
if ($isDebug) {
218225
$jsonFlags = JSON_PRETTY_PRINT | $jsonFlags;
219226
}

test/ProblemDetailsResponseFactoryFactoryTest.php

+5-6
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ public function testLackOfConfigServiceResultsInFactoryUsingDefaults() : void
8282
$this->assertInstanceOf(ProblemDetailsResponseFactory::class, $factory);
8383
$this->assertAttributeSame(ProblemDetailsResponseFactory::EXCLUDE_THROWABLE_DETAILS, 'isDebug', $factory);
8484
$this->assertAttributeSame(
85-
JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION,
85+
JSON_UNESCAPED_SLASHES
86+
| JSON_UNESCAPED_UNICODE
87+
| JSON_PRESERVE_ZERO_FRACTION
88+
| JSON_PARTIAL_OUTPUT_ON_ERROR,
8689
'jsonFlags',
8790
$factory
8891
);
@@ -103,11 +106,7 @@ public function testUsesPrettyPrintFlagOnEnabledDebugMode() : void
103106
$factoryFactory = new ProblemDetailsResponseFactoryFactory();
104107
$factory = $factoryFactory($this->container->reveal());
105108

106-
$this->assertAttributeSame(
107-
JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION,
108-
'jsonFlags',
109-
$factory
110-
);
109+
$this->assertSame(JSON_PRETTY_PRINT, Assert::readAttribute($factory, 'jsonFlags') & JSON_PRETTY_PRINT);
111110
}
112111

113112
public function testUsesDebugSettingFromConfigWhenPresent() : void

test/ProblemDetailsResponseFactoryTest.php

+39
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class ProblemDetailsResponseFactoryTest extends TestCase
3939
/** @var ProblemDetailsResponseFactory */
4040
private $factory;
4141

42+
private const UTF_8_INVALID_2_OCTET_SEQUENCE = "\xc3\x28";
43+
4244
protected function setUp() : void
4345
{
4446
$this->request = $this->prophesize(ServerRequestInterface::class);
@@ -432,4 +434,41 @@ function () {
432434

433435
$this->assertSame($this->response->reveal(), $response);
434436
}
437+
438+
public function testRenderWithMalformedUtf8Sequences(): void
439+
{
440+
$e = $this->prophesize(RuntimeException::class)->willImplement(ProblemDetailsExceptionInterface::class);
441+
$e->getStatus()->willReturn(400);
442+
$e->getDetail()->willReturn('Exception details');
443+
$e->getTitle()->willReturn('Invalid client request');
444+
$e->getType()->willReturn('https://example.com/api/doc/invalid-client-request');
445+
$e->getAdditionalData()->willReturn([
446+
'malformed-utf8' => self::UTF_8_INVALID_2_OCTET_SEQUENCE,
447+
]);
448+
449+
$this->request->getHeaderLine('Accept')->willReturn('application/json');
450+
451+
$stream = $this->prophesize(StreamInterface::class);
452+
$this->preparePayloadForJsonResponse(
453+
$stream,
454+
function (array $payload) {
455+
Assert::arrayHasKey('malformed-utf8', $payload);
456+
}
457+
);
458+
459+
$this->response->getBody()->will([$stream, 'reveal']);
460+
$this->response->withStatus(400)->will([$this->response, 'reveal']);
461+
$this->response->withHeader('Content-Type', 'application/problem+json')->will([$this->response, 'reveal']);
462+
463+
$factory = new ProblemDetailsResponseFactory(function () {
464+
return $this->response->reveal();
465+
});
466+
467+
$response = $factory->createResponseFromThrowable(
468+
$this->request->reveal(),
469+
$e->reveal()
470+
);
471+
472+
$this->assertSame($this->response->reveal(), $response);
473+
}
435474
}

0 commit comments

Comments
 (0)