Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

estimate users' upload speed without direct permission [closed]

I would like to get a rough estimate of the users' upload speed without getting direct permission. This is only to distinguish really slow connections from very fast ones so accuracy is not super important...

like image 519
Kiarash Avatar asked Mar 18 '13 08:03

Kiarash


1 Answers

Here's an implementation of this using XMLHttpRequest expanding on @Yiğit Yener's idea.

Upload speed is dependent on two things: the user's connection speed and the server's connection speed. I made the assumption here that you want to test the speed between the user and your server. And with XMLHttpRequest, that's really the only option because of the same-origin policy.

With upload speed, you don't need to return anything. You just need to POST a large chunk of data to any page on your server. The easiest page to hit is the one you're already on. To do this you can leave the domain portion of the url out altogether in .open(). POST data is limited on some servers to two megabytes, so I used one to be safe. One is enough to get a decent reading.

To prevent the URL from being cached, I append a random number to the end.

url = '?cache=' + Math.floor( Math.random() * 10000 )

To prevent the POST data from being gzipped, I use random data. The function allows you to pass the number of iterations you wish to check. Iterations are spaced out to every five seconds. The update callback gets called each iteration with the speed of that check, and the moving average of all the checks. Use as many iterations as you wish to get your desired accuracy. If you just want a rough estimate, one iteration is enough.

It's called like this:

checkUploadSpeed( 10, function ( speed, average ) {

} );

Demos

You can try this code here.

Private Server

You can try this on ThinkingStiff's own server, which is probably the fastest out of these all.

Stack Snippet

    function checkUploadSpeed( iterations, update ) {
        var average = 0,
            index = 0,
            timer = window.setInterval( check, 5000 ); //check every 5 seconds
        check();

        function check() {
            var xhr = new XMLHttpRequest(),
                url = '?cache=' + Math.floor( Math.random() * 10000 ), //random number prevents url caching
                data = getRandomString( 1 ), //1 meg POST size handled by all servers
                startTime,
                speed = 0;
            xhr.onreadystatechange = function ( event ) {
                if( xhr.readyState == 4 ) {
                    speed = Math.round( 1024 / ( ( new Date() - startTime ) / 1000 ) );
                    average == 0 
                        ? average = speed 
                        : average = Math.round( ( average + speed ) / 2 );
                    update( speed, average );
                    index++;
                    if( index == iterations ) {
                        window.clearInterval( timer );
                    };
                };
            };
            xhr.open( 'POST', url, true );
            startTime = new Date();
            xhr.send( data );
        };

        function getRandomString( sizeInMb ) {
            var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_+`-=[]\{}|;':,./<>?", //random data prevents gzip effect
                iterations = sizeInMb * 1024 * 1024, //get byte count
                result = '';
            for( var index = 0; index < iterations; index++ ) {
                result += chars.charAt( Math.floor( Math.random() * chars.length ) );
            };     
            return result;
        };
    };
    
    checkUploadSpeed( 10, function ( speed, average ) {
        document.getElementById( 'speed' ).textContent = 'speed: ' + speed + 'kbs';
        document.getElementById( 'average' ).textContent = 'average: ' + average + 'kbs';
    } );
<div id="speed">speed: 0kbs</div>
<div id="average">average: 0kbs</div>

JSFiddle

JSFiddle servers where the demo is hosted are slower.

Click this button to go to the fiddle:

JSFiddle

like image 101
ThinkingStiff Avatar answered Sep 21 '22 16:09

ThinkingStiff