-
Notifications
You must be signed in to change notification settings - Fork 22
fix(read stream) consume buffer multiple times #53
base: master
Are you sure you want to change the base?
Conversation
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.
Minor changes, but I like the PR, thanks!
Connection/Connection.php
Outdated
$address | ||
); | ||
$this->_remoteAddress = !empty($address) ? $address : null; | ||
if (0 === $readLength) { |
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 would use 0 >= $readLength
in case of $readLength
is lower than 0.
Connection/Connection.php
Outdated
$buffer = fread($this->getStream(), $readLength); | ||
|
||
if ('' === $buffer) { | ||
$buffer = false; |
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.
Can we use another variable to stop the loop please? Something like $break
. Alternatively, an infinite loop with a break
would fit too.
Travis is failing because our test suites do not work on this environment. I don't know why yet. Anyway, the PR looks good! Should we merge #50 before? |
We can merge this one first, I will adapt #50 when php5.x will be dropped. |
When is this going to be merged in? Websocket server is not really usable without this. |
@Pierozi Keep in mind that this single fix is not enough.
results in stream_socket_recvfrom waiting for message longer than the one actually sent. |
the buffer 2048 it's only for the handshake, it should be lower than that, expect if insert very long content in headers. |
@Pierozi
It keeps looping trying to read the string that is not there. |
the read method should stop at length or EOF according the result of |
@Pierozi
PHP Version 7.0.20 |
I wait your issue to be fixed to merge this PR. |
@Pierozi public function read($length, $flags = 0, $keepReading = true)
{
if (null === $this->getStream()) {
throw new Socket\Exception(
'Cannot read because socket is not established, ' .
'i.e. not connected.',
1
);
}
if (0 > $length) {
throw new Socket\Exception(
'Length must be greater than 0, given %d.',
2,
$length
);
}
$out = '';
do {
$readLength = $length - strlen($out);
if (0 >= $readLength) {
break;
}
if (true === $this->isEncrypted()) {
$buffer = fread($this->getStream(), $readLength);
} else {
$buffer = stream_socket_recvfrom($this->getStream(), $readLength, $flags);
}
if ('' !== $buffer && is_string($buffer)) {
$out .= $buffer;
} else {
break;
}
}
while ($keepReading);
return $out;
} and then changing socket/Server and socket/Client to use it: $buffer = $connection->read(2048, 0, false); but there must be a better solution. |
So, I've taken some time to deep dive into this issue. My original patch works great when Stream is not in blocking mode, and solve the issue related to read large stream. But with We cannot assume to stop if the first result is less than the number of bytes we seeking because we are not sure of the size of the block returned. In my test, even when
Backward CompatibilityBy introducing keepReading false defaultAnyone who wants to consume large stream will need to set the boolean to true I vote for BC break because read length should be the natural behavior of the read method. |
@Hywan ping there |
Connection/Connection.php
Outdated
@@ -681,21 +683,31 @@ public function read($length, $flags = 0) | |||
); | |||
} | |||
|
|||
if (true === $this->isEncrypted()) { | |||
return fread($this->getStream(), $length); | |||
if (is_int($chunk)) { |
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.
- if (is_int($chunk))
+ if (is_int($chunk) && 0 < $chunk))
to ensure the chunk is greater than zero. Could it be greater than or equal to zero?
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 right! never trust the userland!
Connection/Connection.php
Outdated
if (true === $this->isEncrypted()) { | ||
return fread($this->getStream(), $length); | ||
if (is_int($chunk)) { | ||
stream_set_chunk_size($this->getStream(), $chunk); |
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 we collect the previous chunk size (returned by stream_set_chunk_size
) and restore it just after the call? I'm not sure how it acts with concurrent accesses…
@Pierozi Can we guess the default value for |
I need to check related to |
@Hywan detection using First thought was to use |
Issue related to WebSocket hoaproject/Websocket#95
We need to consume the stream until the
length
bytes are reach or the end of stream (if user try to get more than expected)stream_socket_recvfrom
return false andfread
empty value.I've remove the read related to
remoteAddress
because it will be removed soon on the PR #50