austgl / phpws

Automatically exported from code.google.com/p/phpws
0 stars 0 forks source link

Function readWholeBuffer causes issues on SSL connections #20

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Hi,

Above all, i know that secure SSL support are not fully tested.

When using SSL, readWholeBuffer doesn't work very well (after some research).
If fact, it seems that $metadata['unread_bytes'] causes the error. And in the 
PHP doc, i can read : "Note: You shouldn't use this value in a script."

If you print the buffer (with SSL activated) it is always "G" (The "G" of "GET 
....")

So i tried this :

public static function readWholeBuffer($resource){
        $buffer = '';
        $buffsize = 8192;

        $metadata['unread_bytes'] = 0;

        /*do{
            if(feof($resource))
            {
                return false;
            }

            $result = fread($resource, $buffsize);
            if($result === false || feof($resource))
            {
                    return false;
            }
            $buffer .= $result;

            $metadata = stream_get_meta_data($resource);

            $buffsize = min($buffsize, $metadata['unread_bytes']);

        } while($metadata['unread_bytes'] > 0);*/

        do {
            $result = fread($resource, $buffsize);

            if( $result === false ) {
                return false;
            }

            $buffer .= $result;

            $metadata = stream_get_meta_data($resource);
        } while( !feof($resource) );

        return $buffer;
}

It is working with SSL but not without SSL (it's blocking on the 'fread' 
instruction). Any Ideas ?

I'm using Google Chrome 17 ( Sec-WebSocket-Version: 13 ) and php 5.2.9 ( i've 
changed websocket.server.php a little to make it work with 5.2.9 )

Regards,

Vince

Original issue reported on code.google.com by and1hots...@gmail.com on 1 Mar 2012 at 9:13

GoogleCodeExporter commented 9 years ago
Nope, my code doesn't work with SSL either.
After read all the headers (but not only the "G"), it's also blocking on 
fread...

Original comment by and1hots...@gmail.com on 1 Mar 2012 at 9:28

GoogleCodeExporter commented 9 years ago
This seems to work.

First a set the stream as non-blocking,
I read the socket until I am no longer receiving data ( i.e. fread() return '', 
i.e. strlen(fread()) is nul)
After reading, i set the stream as blocking (as before the read) and return the 
buffer

public static function readWholeBuffer($resource){
    $buffer = '';
    $buffsize = 8192;

    $metadata['unread_bytes'] = 0;

    stream_set_blocking($resource, 0);

    while( !feof($resource) ) {

        $result = fread($resource, $buffsize);

        if( $result === false ) {
                return false;
        }

        if( strlen($result) == 0 ) {
                break;
        }

        $buffer .= $result;

    }

    stream_set_blocking($resource, 1);

    return $buffer;
}

Original comment by and1hots...@gmail.com on 1 Mar 2012 at 11:13

GoogleCodeExporter commented 9 years ago
$metadata array is not used anymore.

public static function readWholeBuffer($resource){
    $buffer = '';
    $buffsize = 8192;

    stream_set_blocking($resource, 0);

    while( !feof($resource) ) {

        $result = fread($resource, $buffsize);

        if( $result === false ) {
                return false;
        }

        if( strlen($result) == 0 ) {
                break;
        }

        $buffer .= $result;

    }

    stream_set_blocking($resource, 1);

    return $buffer;
}

Original comment by and1hots...@gmail.com on 1 Mar 2012 at 11:15

GoogleCodeExporter commented 9 years ago
Thanks for your adjustments. I will test them out on my server. When the server 
is still stable I will commit your changes.

Again, thanks a lot for your help!

Chris

Original comment by ch...@devristo.com on 1 Mar 2012 at 3:49

GoogleCodeExporter commented 9 years ago
You're welcome. You've made a nice work too

I already try it and I'll post if I find bugs;-)

Vincent

Original comment by and1hots...@gmail.com on 1 Mar 2012 at 4:01

GoogleCodeExporter commented 9 years ago
Thanks, I just had a minor hickup. Not sure if it has to do with your changes. 
After a restart it works fine.

To be sure I will wait a day or two before committing the changes :)

BTW: Did you manage to get SSL to work?

Original comment by ch...@devristo.com on 1 Mar 2012 at 4:06

GoogleCodeExporter commented 9 years ago
Hmmm, again a hickup. Weird.

Original comment by ch...@devristo.com on 1 Mar 2012 at 4:07

GoogleCodeExporter commented 9 years ago
This part seems incorrect due to the nature of non blocking sockets.

[[if( strlen($result) == 0 ) {
break;
}]]

It will break too soon if there is still data in transit.

Original comment by ch...@devristo.com on 1 Mar 2012 at 4:13

GoogleCodeExporter commented 9 years ago
I see what you mean. But I didn't had this problem today. Maybe it will appear 
with a (very) slow connection ?

Yes i'm using it with SSL with success (for one global control socket and 
others to upload files (so with a lot of send()). It works great.

Is there an other way to know if all data sent has been received ?

Regards

Original comment by and1hots...@gmail.com on 1 Mar 2012 at 4:52

GoogleCodeExporter commented 9 years ago
I am not sure. I have had similar problems before, after using the meta data 
(which I know is not correct) it was fixed. PHPWS was my first socket related 
project, so I am quite sure I missed the obvious, correct, solution.

Original comment by ch...@devristo.com on 1 Mar 2012 at 5:25

GoogleCodeExporter commented 9 years ago
In this link ( http://www.php.net/manual/fr/function.stream-get-contents.php ) 
i can read this :

"clarck dot smith at gmail dot com 17-Dec-2011 07:12 :

In that case when stream_get_contents/fread/fgets or other stream reading 
functions block indefinitely your script because they don't reached the limit 
of bytes to read use the socket_get_meta_data function to figure out the number 
of the bytes to read. It returns an array that contains a key named 
'unread_bytes' and then pass that number to your favourite stream reading 
functions second parameter to read from the stream.

Maybe a good workaround to use the stream_select function, and set the socket 
to non-blocking mode with the use of stream_set_blocking($stream, 0). In this 
case the socket reading functions work properly.

Cheers, Ervin"

It is the case with my function because you are already using stream_select.

Original comment by and1hots...@gmail.com on 1 Mar 2012 at 6:06

GoogleCodeExporter commented 9 years ago
Yeah I use socket select, but without blocking mode. Your solution, unblock the 
socket temporarily, should be fine. However I dont have time right now to fix 
the bug that it causes.

Original comment by ch...@devristo.com on 2 Mar 2012 at 5:40

GoogleCodeExporter commented 9 years ago
Currently I am testing:

public static function readWholeBuffer($resource){
        $buffer = '';
        $buffsize = 8192;

        stream_set_blocking($resource,0);

        $chunk = '';
        do{
             $chunk = fread($resource, $buffsize);

             if(is_string($chunk))
                $buffer .= $chunk;

        }while(is_string($chunk) && strlen($chunk) > 0);

        stream_set_blocking($resource,1);

        return $buffer;
    }

Original comment by ch...@devristo.com on 2 Mar 2012 at 5:58

GoogleCodeExporter commented 9 years ago
Seems to work here (no ssl though)

Original comment by ch...@devristo.com on 2 Mar 2012 at 8:50

GoogleCodeExporter commented 9 years ago
Why do you test if $chunk is a string ?

Google Chrome already allows sending binary data through websockets (like it is 
defined in the Web Socket API in the W3C 
(http://dev.w3.org/html5/websockets/#dom-websocket-binarytype)). 

In my project, when i upload a file using websocket, i use binary data when 
it's possible. Mainly because the size of a binary chunk is smaller than the 
size of this chunk base64 encoded. So the overall data is less not base64 
encoded (and so the upload goes faster)

Original comment by and1hots...@gmail.com on 2 Mar 2012 at 9:23

GoogleCodeExporter commented 9 years ago
Oh... i forgot... Today i uses my "readWholeBuffer" function all the day and 
there were no problem.

Your "readWholeBuffer" function does the same that mine but i think that using 
"feof" is more suitable. And i don't think that testing if $chunk is a string 
is a good solution.

Original comment by and1hots...@gmail.com on 2 Mar 2012 at 9:29

GoogleCodeExporter commented 9 years ago
Sorry for the flood. I'm using SSL Web Sockets for my project ;-)

Original comment by and1hots...@gmail.com on 2 Mar 2012 at 9:30

GoogleCodeExporter commented 9 years ago
Could have checked on === FALSE as well, since fread only returns FALSE or a 
string. With your code I had several drop outs, messages not being received at 
all in the chat I use it in. What the reason is of that I don't know, I just 
know that the snippet I posted works fine here :)

Already editted out the is_string() on my test server :)

PS: a string in php could just as well be binary data, thats why strlen doesnt 
work on multi-byte strings. I am not sure if binary support requires a new 
protocol version, if not I guess it should work already with phpws.

Original comment by ch...@devristo.com on 2 Mar 2012 at 10:05

GoogleCodeExporter commented 9 years ago
So what's your current version of "readWholeBuffer" ? i will try it here with 
my project (with SSL)

Original comment by and1hots...@gmail.com on 2 Mar 2012 at 10:21

GoogleCodeExporter commented 9 years ago
Unfortunately I had some issues again this morning, so it seems my solution was 
not perfect either :/

Original comment by ch...@devristo.com on 3 Mar 2012 at 6:01

GoogleCodeExporter commented 9 years ago

Original comment by ch...@devristo.com on 30 May 2012 at 7:16

GoogleCodeExporter commented 9 years ago
Hi guys!

Any progress with this issue?

Original comment by zoltan.l...@gmail.com on 24 May 2013 at 11:04