-
-
Notifications
You must be signed in to change notification settings - Fork 167
Protect the TCP connection against close from other streams #133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
src/Server.php
Outdated
// Forward occuring errors on to request | ||
$stream->on('error', function ($error) use ($request) { | ||
$request->emit('error', array($error)); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was probably prepared before #132 was in, this should now be moved to the Request
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must be slipped through in a rebase 🙈 . It was already moved to the Request object. Removed it.
use React\Stream\Util; | ||
|
||
/** @internal */ | ||
class CloseProtectionStream extends EventEmitter implements ReadableStreamInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The class LGTM, but I suppose its purpose may be a bit unclear for outsiders ;-) Can you add some documentation here? 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a description. Have look. Tell me if I missed a point.
tests/CloseProtectionStreamTest.php
Outdated
|
||
class CloseProtectionStreamTest extends TestCase | ||
{ | ||
public function testCloseEventDoesntCloseInputStream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what does it do instead? :-)
tests/CloseProtectionStreamTest.php
Outdated
$input->expects($this->once())->method('pause'); | ||
|
||
$protection = new CloseProtectionStream($input); | ||
$protection->pause(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is a duplicate of a test below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. Must be leftover of a previous local version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@legionth ping?
src/CloseProtectionStream.php
Outdated
public function handleError(\Exception $e) | ||
{ | ||
$this->emit('error', array($e)); | ||
$this->close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not saying this is wrong, but the close()
is probably not needed currently and may be an issue with the future Stream version (in case this is a non-permanent error). I guess it's probably safer to leave the close()
out here and leave this up to the input stream?
tests/CloseProtectionStreamTest.php
Outdated
$protection->on('close', $this->expectCallableOnce()); | ||
|
||
$input->close(); | ||
$input->emit('end', array()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like an invalid sequence of events to me, what is being tested here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was a leftover of previous version. Removed it.
$input->emit('end', array()); | ||
|
||
$this->assertFalse($protection->isReadable()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above, is this a duplicate?
$this->emit('close'); | ||
|
||
// 'pause' the stream avoids additional traffic transferred by this stream | ||
$this->input->pause(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see this covered, but what happens if I call this:
$protection->close();
$protection->resume();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, this wasn't handled correctly. Fixed it and added some tests for it.
tests/ServerTest.php
Outdated
$server->on('request', function ($request, $response) use (&$error){ | ||
$request->on('error', function ($ex) use (&$error) { | ||
$error = $ex; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this use expectCallableOnce()
instead? (see also below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this, too. But I wanted to ensure that the expected type is an Exception
and nothing else. Do you think it is enough to check this behavior in ChunkedDecoderTest
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the curren commits only expectCallableOnce
will be called and not the assertion of an Exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the updated tests are easier to grasp 👍 IF the exception class is really important here (I'm undecided about this), then you may want to use expectCallableOnceWith(…)
and family?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point! Added that in the newest commit.
tests/ServerTest.php
Outdated
$this->assertInstanceOf('InvalidArgumentException', $error); | ||
} | ||
|
||
public function testInvalidChunkHeaderResultsInErrorResponse() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaict this does not "result in error reponse", but actually "result in an error on the request stream"?
These tests (see below) LGTM otherwise, but I'm not sure if they provide much value in ServerTest
or if we should re-organize this? Any input would be welcome 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-organize in which way?
I wanted to show that the server can handle the errors thrown by the ChunkedDecoder
and the LengthLimitedStream
. Do you think these tests are not necessary? Or is it the similar logic for these tests that concerns you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the test names.
I consider to reorganize it in a seprated PR. Currently the ServerTest
is more an integration test than an unit test. That is completly fine but maybe this should be seperated. I would keep the tests in this PR, because this would affect several other tests too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The updated tests now look good to me and I agree that it makes sense to re-organize this in a later follow-up PR 👍
0572c12
to
1318841
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests could use an update, otherwise LGTM 👍
tests/CloseProtectionStreamTest.php
Outdated
$input->expects($this->once())->method('pause'); | ||
|
||
$protection = new CloseProtectionStream($input); | ||
$protection->pause(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@legionth ping?
tests/CloseProtectionStreamTest.php
Outdated
$protection->close(); | ||
} | ||
|
||
public function testPause() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the test names (and below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored this, I hope the names are easier to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! 👍
Just squashed the commits. |
Updated the commit history and added an README update. |
Currently the
ChunkedDecoder
and theLengthLimitedStream
emit errors, but these errors aren't handled anywhere.This takes care that theses errors will be forwarded to the request object.
This PR also adds an CloseProtectionStream to protect the TCP connection against a close , when an error occurs in any stream. Instead of closing the TCP stream it will be paused, similar to the current behavior of the request object.