Skip to content

Commit 2748115

Browse files
committed
Improve error messages for invalid responses
1 parent 445e314 commit 2748115

File tree

2 files changed

+74
-9
lines changed

2 files changed

+74
-9
lines changed

src/EventSource.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,20 @@ private function request()
193193
$this->request->then(function (ResponseInterface $response) {
194194
if ($response->getStatusCode() !== 200) {
195195
$this->readyState = self::CLOSED;
196-
$this->emit('error', array(new \UnexpectedValueException('Unexpected status code')));
196+
$this->emit('error', [new \UnexpectedValueException(
197+
'Expected "200 OK" response status, ' . $this->quote($response->getStatusCode() . ' ' . $response->getReasonPhrase()) . ' response status returned'
198+
)]);
197199
$this->close();
198200
return;
199201
}
200202

201203
// match `Content-Type: text/event-stream` (case insensitive and ignore additional parameters)
202-
if (!preg_match('/^text\/event-stream(?:$|;)/i', $response->getHeaderLine('Content-Type'))) {
204+
$contentType = $response->getHeaderLine('Content-Type');
205+
if (!preg_match('/^text\/event-stream(?:$|;)/i', $contentType)) {
203206
$this->readyState = self::CLOSED;
204-
$this->emit('error', array(new \UnexpectedValueException('Unexpected Content-Type')));
207+
$this->emit('error', [new \UnexpectedValueException(
208+
'Expected "Content-Type: text/event-stream" response header, ' . (!$response->hasHeader('Content-Type') ? 'no "Content-Type"' : $this->quote('Content-Type: ' . $contentType)) . ' response header returned'
209+
)]);
205210
$this->close();
206211
return;
207212
}
@@ -290,4 +295,14 @@ public function close()
290295

291296
$this->removeAllListeners();
292297
}
298+
299+
/**
300+
* @param string $string
301+
* @return string
302+
* @throws void
303+
*/
304+
private function quote($string)
305+
{
306+
return '"' . \addcslashes(\substr($string, 0, 100), "\x00..\x1f\"\\\x7f..\xff") . '"';
307+
}
293308
}

tests/EventSourceTest.php

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,28 @@ public function testCloseAfterGetRequestFromConstructorFailsWillCancelPendingRet
228228
$es->close();
229229
}
230230

231-
public function testConstructorWillReportFatalErrorWhenGetResponseResolvesWithInvalidStatusCode()
231+
public function provideInvalidStatusCode()
232+
{
233+
return [
234+
[
235+
new Response(400, ['Content-Type' => 'text/event-stream'], ''),
236+
'Expected "200 OK" response status, "400 Bad Request" response status returned'
237+
],
238+
[
239+
new Response(500, ['Content-Type' => 'text/event-stream'], '', '1.1', "Intern\xE4l Server Err\xF6r"),
240+
'Expected "200 OK" response status, "500 Intern\344l Server Err\366r" response status returned'
241+
],
242+
[
243+
new Response(400, ['Content-Type' => 'text/event-stream'], '', '1.1', str_repeat('a', 200)),
244+
'Expected "200 OK" response status, "400 ' . str_repeat('a', 96) . '" response status returned'
245+
]
246+
];
247+
}
248+
249+
/**
250+
* @dataProvider provideInvalidStatusCode
251+
*/
252+
public function testConstructorWillReportFatalErrorWhenGetResponseResolvesWithInvalidStatusCode($response, $expectedMessage)
232253
{
233254
$deferred = new Deferred();
234255
$browser = $this->getMockBuilder('React\Http\Browser')->disableOriginalConstructor()->getMock();
@@ -244,14 +265,43 @@ public function testConstructorWillReportFatalErrorWhenGetResponseResolvesWithIn
244265
$caught = $e;
245266
});
246267

247-
$response = new Response(400, array('Content-Type' => 'text/event-stream'), '');
248268
$deferred->resolve($response);
249269

250270
$this->assertEquals(EventSource::CLOSED, $readyState);
251271
$this->assertInstanceOf('UnexpectedValueException', $caught);
252-
}
253-
254-
public function testConstructorWillReportFatalErrorWhenGetResponseResolvesWithInvalidContentType()
272+
$this->assertEquals($expectedMessage, $caught->getMessage());
273+
}
274+
275+
public function provideInvalidContentType()
276+
{
277+
return [
278+
[
279+
new Response(200, [], ''),
280+
'Expected "Content-Type: text/event-stream" response header, no "Content-Type" response header returned'
281+
],
282+
[
283+
new Response(200, ['Content-Type' => ''], ''),
284+
'Expected "Content-Type: text/event-stream" response header, "Content-Type: " response header returned'
285+
],
286+
[
287+
new Response(200, ['Content-Type' => 'text/html'], ''),
288+
'Expected "Content-Type: text/event-stream" response header, "Content-Type: text/html" response header returned'
289+
],
290+
[
291+
new Response(200, ['Content-Type' => "application/json; invalid=a\xE4b"], ''),
292+
'Expected "Content-Type: text/event-stream" response header, "Content-Type: application/json; invalid=a\344b" response header returned'
293+
],
294+
[
295+
new Response(200, ['Content-Type' => str_repeat('a', 200)], ''),
296+
'Expected "Content-Type: text/event-stream" response header, "Content-Type: ' . str_repeat('a', 86) . '" response header returned'
297+
]
298+
];
299+
}
300+
301+
/**
302+
* @dataProvider provideInvalidContentType
303+
*/
304+
public function testConstructorWillReportFatalErrorWhenGetResponseResolvesWithInvalidContentType($response, $expectedMessage)
255305
{
256306
$deferred = new Deferred();
257307
$browser = $this->getMockBuilder('React\Http\Browser')->disableOriginalConstructor()->getMock();
@@ -267,11 +317,11 @@ public function testConstructorWillReportFatalErrorWhenGetResponseResolvesWithIn
267317
$caught = $e;
268318
});
269319

270-
$response = new Response(200, array(), '');
271320
$deferred->resolve($response);
272321

273322
$this->assertEquals(EventSource::CLOSED, $readyState);
274323
$this->assertInstanceOf('UnexpectedValueException', $caught);
324+
$this->assertEquals($expectedMessage, $caught->getMessage());
275325
}
276326

277327
public function testConstructorWillReportOpenWhenGetResponseResolvesWithValidResponse()

0 commit comments

Comments
 (0)