Skip to content

Commit 0ddb503

Browse files
committed
Close inactive requests
This builds on top of #405 and further builds out #423 by also close connections with inactive requests.
1 parent 997d5b6 commit 0ddb503

File tree

4 files changed

+129
-65
lines changed

4 files changed

+129
-65
lines changed

src/Io/RequestHeaderParser.php

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Evenement\EventEmitter;
66
use Psr\Http\Message\ServerRequestInterface;
7+
use React\EventLoop\LoopInterface;
78
use React\Http\Message\Response;
89
use React\Http\Message\ServerRequest;
910
use React\Socket\ConnectionInterface;
@@ -24,12 +25,51 @@ class RequestHeaderParser extends EventEmitter
2425
{
2526
private $maxSize = 8192;
2627

27-
public function handle(ConnectionInterface $conn)
28+
/**
29+
* @var LoopInterface
30+
*/
31+
private $loop;
32+
33+
/**
34+
* @var float
35+
*/
36+
private $idleConnectionTimeout;
37+
38+
/**
39+
* @param LoopInterface $loop
40+
* @param float $idleConnectionTimeout
41+
*/
42+
public function __construct(LoopInterface $loop, $idleConnectionTimeout)
2843
{
44+
$this->loop = $loop;
45+
$this->idleConnectionTimeout = $idleConnectionTimeout;
46+
}
47+
48+
/**
49+
* @param bool $firstRequest
50+
*/
51+
public function handle(ConnectionInterface $conn, $firstRequest = true)
52+
{
53+
$loop = $this->loop;
54+
$idleConnectionTimeout = $this->idleConnectionTimeout;
55+
$createTimer = function () use ($conn, $loop, $idleConnectionTimeout, $firstRequest) {
56+
return $loop->addTimer($idleConnectionTimeout, function () use ($conn, $firstRequest) {
57+
if ($firstRequest) {
58+
$conn->write("HTTP/1.0 " . Response::STATUS_REQUEST_TIMEOUT . " Request Timed Out\r\n");
59+
}
60+
$conn->close();
61+
});
62+
};
63+
$timer = $createTimer();
64+
$conn->on('close', function () use ($loop, $timer) {
65+
$loop->cancelTimer($timer);
66+
});
2967
$buffer = '';
3068
$maxSize = $this->maxSize;
3169
$that = $this;
32-
$conn->on('data', $fn = function ($data) use (&$buffer, &$fn, $conn, $maxSize, $that) {
70+
$conn->on('data', $fn = function ($data) use (&$buffer, &$fn, $conn, $maxSize, $that, $loop, &$timer, $createTimer) {
71+
$loop->cancelTimer($timer);
72+
$timer = $createTimer();
3373
// append chunk of data to buffer and look for end of request headers
3474
$buffer .= $data;
3575
$endOfHeader = \strpos($buffer, "\r\n\r\n");
@@ -43,6 +83,7 @@ public function handle(ConnectionInterface $conn)
4383
new \OverflowException("Maximum header size of {$maxSize} exceeded.", Response::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE),
4484
$conn
4585
));
86+
$loop->cancelTimer($timer);
4687
return;
4788
}
4889

@@ -67,6 +108,7 @@ public function handle(ConnectionInterface $conn)
67108
$exception,
68109
$conn
69110
));
111+
$loop->cancelTimer($timer);
70112
return;
71113
}
72114

@@ -105,6 +147,7 @@ public function handle(ConnectionInterface $conn)
105147
if ($contentLength === 0) {
106148
$stream->emit('end');
107149
$stream->close();
150+
$loop->cancelTimer($timer);
108151
}
109152
});
110153
}

src/Io/StreamingServer.php

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public function __construct(LoopInterface $loop, $requestHandler, $idleConnectTi
111111
$this->idleConnectionTimeout = $idleConnectTimeout;
112112

113113
$this->callback = $requestHandler;
114-
$this->parser = new RequestHeaderParser();
114+
$this->parser = new RequestHeaderParser($this->loop, $this->idleConnectionTimeout);
115115

116116
$that = $this;
117117
$this->parser->on('headers', function (ServerRequestInterface $request, ConnectionInterface $conn) use ($that) {
@@ -142,23 +142,9 @@ public function listen(ServerInterface $socket)
142142
}
143143

144144
/** @internal */
145-
public function handle(ConnectionInterface $conn)
145+
public function handle(ConnectionInterface $conn, $firstRequest = true)
146146
{
147-
$timer = $this->loop->addTimer($this->idleConnectionTimeout, function () use ($conn) {
148-
$conn->close();
149-
});
150-
$loop = $this->loop;
151-
$conn->once('data', function () use ($loop, $timer) {
152-
$loop->cancelTimer($timer);
153-
});
154-
$conn->on('end', function () use ($loop, $timer) {
155-
$loop->cancelTimer($timer);
156-
});
157-
$conn->on('close', function () use ($loop, $timer) {
158-
$loop->cancelTimer($timer);
159-
});
160-
161-
$this->parser->handle($conn);
147+
$this->parser->handle($conn, $firstRequest);
162148
}
163149

164150
/** @internal */
@@ -374,7 +360,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt
374360

375361
// either wait for next request over persistent connection or end connection
376362
if ($persist) {
377-
$this->handle($connection);
363+
$this->handle($connection, false);
378364
} else {
379365
$connection->end();
380366
}
@@ -398,7 +384,7 @@ public function handleResponse(ConnectionInterface $connection, ServerRequestInt
398384
$that = $this;
399385
$body->on('end', function () use ($connection, $that, $body) {
400386
$connection->removeListener('close', array($body, 'close'));
401-
$that->handle($connection);
387+
$that->handle($connection, false);
402388
});
403389
} else {
404390
$body->pipe($connection);

0 commit comments

Comments
 (0)