Skip to content

Commit ce64116

Browse files
authored
Merge pull request #91 from clue-labs/cancel
Request::close() now cancels pending connection attempt
2 parents e5dcc27 + 6266cab commit ce64116

4 files changed

Lines changed: 95 additions & 23 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ point buffered data will be sent and all further data will be ignored.
2525
The `Request#close()` method can be used to
2626
forefully close sending the request.
2727
Unlike the `end()` method, this method discards any buffers and closes the
28-
underlying connection.
28+
underlying connection if it is already established or cancels the pending
29+
connection attempt otherwise.
2930

3031
Request implements WritableStreamInterface, so a Stream can be piped to it.
3132
Interesting events emitted by Request:

src/Request.php

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,35 +54,38 @@ private function writeHead()
5454
$stateRef = &$this->state;
5555
$pendingWrites = &$this->pendingWrites;
5656

57-
$this
58-
->connect()
59-
->done(
60-
function (ConnectionInterface $stream) use ($requestData, &$streamRef, &$stateRef, &$pendingWrites) {
61-
$streamRef = $stream;
57+
$promise = $this->connect();
58+
$promise->done(
59+
function (ConnectionInterface $stream) use ($requestData, &$streamRef, &$stateRef, &$pendingWrites) {
60+
$streamRef = $stream;
6261

63-
$stream->on('drain', array($this, 'handleDrain'));
64-
$stream->on('data', array($this, 'handleData'));
65-
$stream->on('end', array($this, 'handleEnd'));
66-
$stream->on('error', array($this, 'handleError'));
67-
$stream->on('close', array($this, 'handleClose'));
62+
$stream->on('drain', array($this, 'handleDrain'));
63+
$stream->on('data', array($this, 'handleData'));
64+
$stream->on('end', array($this, 'handleEnd'));
65+
$stream->on('error', array($this, 'handleError'));
66+
$stream->on('close', array($this, 'handleClose'));
6867

69-
$headers = (string) $requestData;
68+
$headers = (string) $requestData;
7069

71-
$more = $stream->write($headers . $pendingWrites);
70+
$more = $stream->write($headers . $pendingWrites);
7271

73-
$stateRef = Request::STATE_HEAD_WRITTEN;
72+
$stateRef = Request::STATE_HEAD_WRITTEN;
7473

75-
// clear pending writes if non-empty
76-
if ($pendingWrites !== '') {
77-
$pendingWrites = '';
74+
// clear pending writes if non-empty
75+
if ($pendingWrites !== '') {
76+
$pendingWrites = '';
7877

79-
if ($more) {
80-
$this->emit('drain');
81-
}
78+
if ($more) {
79+
$this->emit('drain');
8280
}
83-
},
84-
array($this, 'handleError')
85-
);
81+
}
82+
},
83+
array($this, 'handleError')
84+
);
85+
86+
$this->on('close', function() use ($promise) {
87+
$promise->cancel();
88+
});
8689
}
8790

8891
public function write($data)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace React\Tests\HttpClient;
4+
5+
use React\EventLoop\Factory;
6+
use React\HttpClient\Client;
7+
use React\HttpClient\Response;
8+
9+
/** @group internet */
10+
class FunctionalIntegrationTest extends TestCase
11+
{
12+
public function testSuccessfulResponseEmitsEnd()
13+
{
14+
$loop = Factory::create();
15+
$client = new Client($loop);
16+
17+
$request = $client->request('GET', 'http://www.google.com/');
18+
19+
$once = $this->expectCallableOnce();
20+
$request->on('response', function (Response $response) use ($once) {
21+
$response->on('end', $once);
22+
});
23+
24+
$request->end();
25+
26+
$loop->run();
27+
}
28+
29+
public function testCancelPendingConnectionEmitsClose()
30+
{
31+
$loop = Factory::create();
32+
$client = new Client($loop);
33+
34+
$request = $client->request('GET', 'http://www.google.com/');
35+
$request->on('error', $this->expectCallableNever());
36+
$request->on('close', $this->expectCallableOnce());
37+
$request->end();
38+
$request->close();
39+
40+
$loop->run();
41+
}
42+
}

tests/RequestTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,32 @@ public function endAfterCloseIsNoOp()
516516
$request->end();
517517
}
518518

519+
/**
520+
* @test
521+
*/
522+
public function closeShouldCancelPendingConnectionAttempt()
523+
{
524+
$requestData = new RequestData('POST', 'http://www.example.com');
525+
$request = new Request($this->connector, $requestData);
526+
527+
$promise = new Promise(function () {}, function () {
528+
throw new \RuntimeException();
529+
});
530+
531+
$this->connector->expects($this->once())
532+
->method('connect')
533+
->with('www.example.com:80')
534+
->willReturn($promise);
535+
536+
$request->end();
537+
538+
$request->on('error', $this->expectCallableNever());
539+
$request->on('close', $this->expectCallableOnce());
540+
541+
$request->close();
542+
$request->close();
543+
}
544+
519545
/** @test */
520546
public function requestShouldRelayErrorEventsFromResponse()
521547
{

0 commit comments

Comments
 (0)