Skip to content

Commit

Permalink
Merge 4.2.8
Browse files Browse the repository at this point in the history
* upstream/master:
  Updated doc.md
  add support to disable specific tests when pass "-1" (librespeed#52)
  The time limits are now ignored if the speed is still 0.00 when the limit is reached
  Added link to librespeed#50
  Updated known issues
  Added more troubleshooting
  Added donation info
  Updated README.md
  Removed unused Fetch API support (may come back in future); Removed quirk for Safari, now treated as chromium-based browser
  Added quickstart videos
  Improved custom settings parsing
  Added more common issues in troubleshooting section of doc.md
  Added warning if parsing of custom settings fails
  Added customizable grace time at beginning of tests; GET parameters can now be used in the URLs in the settings; Minor changes
  Fixed a typo in IE11-specific code
  Added configuration for custom compensation factor; Fixed a problem where xhr_ignoreErrors could not be changed
  Improved ping/jitter test
  Added options for managing errors during test (abort/retry/ignore)
  • Loading branch information
Sam Edwards committed Jul 28, 2017
2 parents ce1e4c2 + 6e1a199 commit b495c0e
Show file tree
Hide file tree
Showing 8 changed files with 346 additions and 161 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ugly.bat
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,21 @@ Only modern browsers are supported (IE11, latest Edge, latest Chrome, latest Fir
- Your server must accept large POST requests (up to 20 Megabytes), otherwise the upload test will fail
- It's also better if your server does not use compression, but it's not mandatory

## How to use
## Quick installation videos
* [Debian 9.0 with Apache](https://fdossena.com/?p=speedtest/quickstart_deb.frag)
* [Windows Server 2016 with IIS](https://fdossena.com/?p=speedtest/quickstart_win.frag)

Also, here's an [example config on Ubuntu 16 LTS](https://github.com/adolfintel/speedtest/issues/50)

## How to use in your site
See the examples or doc.md

## Docker
Please see the ```docker``` branch

## Donate
If you want to support this project, you can [send a donation via PayPal](https://www.paypal.me/sineisochronic).

## License
Copyright (C) 2016-2017 Federico Dossena

Expand Down
1 change: 1 addition & 0 deletions apache2_dynamic/php/empty.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Connection: keep-alive");
?>
108 changes: 73 additions & 35 deletions doc.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# HTML5 Speedtest

> by Federico Dossena
> Version 4.2.1, May 15 2017
> Version 4.2.9, July 19 2017
> [https://github.com/adolfintel/speedtest/](https://github.com/adolfintel/speedtest/)

Expand All @@ -24,6 +24,9 @@ First of all, the requirements to run this test:

If this looks good, let's proceed and see how to use the test.

## Quick installation videos
* [Debian 9.0 with Apache](https://fdossena.com/?p=speedtest/quickstart_deb.frag)
* [Windows Server 2016 with IIS](https://fdossena.com/?p=speedtest/quickstart_win.frag)

## Installation
To install the test on your server, upload the following files:
Expand Down Expand Up @@ -108,22 +111,22 @@ format:
* `5` = Test aborted
* __dlStatus__ is either
* Empty string (not started or aborted)
* Download speed in Megabit/s as a number with 2 digits
* Download speed in Megabit/s as a number with 2 decimals
* The string "Fail" (test failed)
* __ulStatus__ is either
* Empty string (not started or aborted)
* Upload speed in Megabit/s as a number with 2 digits
* Upload speed in Megabit/s as a number with 2 decimals
* The string "Fail" (test failed)
* __pingStatus__ is either
* Empty string (not started or aborted)
* Estimated ping in milliseconds as a number with 2 digits
* Estimated ping in milliseconds as a number with 2 decimals
* The string "Fail" (test failed)
* __clientIp__ is either
* Empty string (not fetched yet or failed)
* The client's IP address as a string
* __jitterStatus__ is either
* Empty string (not started or aborted)
* Estimated jitter in milliseconds as a number with 2 digits (lower = stable connection)
* Estimated jitter in milliseconds as a number with 2 decimals (lower = stable connection)
* The string "Fail" (test failed)
* __pointOfTest__ is either
* Empty string for a single server test or failure on list retrieval
Expand All @@ -134,23 +137,23 @@ format:
* __isp__ Internet Service Provider name (http://ipinfo.io/developers#terms-of-use)

### Starting the test
To start the test, send the start command to the worker:
To start the test with the default settings, which is usually the best choice, send the start command to the worker:

```js
w.postMessage('start')
```

This starts the test with the default settings, which is usually the best choice. If you want, you can change these settings and pass them to the worker as JSON with like this:
If you want, you can change these settings and pass them to the worker as JSON when you start it, like this:

```js
w.postMessage('start {"param1": "value1", "param2": "value2", ...}')
```

#### Test parameters
* __time_dl__: How long the download test should be in seconds
* __time_dl__: How long the download test should be in seconds. The test will continue regardless of this limit if the speed is still 0.00 when the limit is reached.
* Default: `15`
* Recommended: `>=5`
* __time_ul__: How long the upload test should be in seconds
* __time_ul__: How long the upload test should be in seconds. The test will continue regardless of this limit if the speed is still 0.00 when the limit is reached.
* Default: `15`
* Recommended: `>=10`
* __count_ping__: How many pings to perform in the ping test
Expand All @@ -159,25 +162,31 @@ w.postMessage('start {"param1": "value1", "param2": "value2", ...}')
* __ping_timeout__: Max wait time for a ping request in milliseconds
* Default: `1000`
* Recommended: `>=10`
* __url_dl__: path to garbage.php or a large file to use for the download test
* Default: `/download/`
* __Important:__ route configured in .htaccess file
* __url_ul__: path to ab empty file or empty.php to use for the upload test
* Default: `/upload`
* __Important:__ route configured in .htaccess file
* __url_dl__: path to garbage.php or a large file to use for the download test.
* Default: `garbage.php`
* The string "-1" disables the test
* __Important:__ path is relative to js file
* __url_ul__: path to an empty file or empty.php to use for the upload test
* Default: `empty.php`
* The string "-1" disables the test
* __Important:__ path is relative to js file
* __url_ping__: path to an empty file or empty.php to use for the ping test
* Default: `/ping`
* __Important:__ route configured in .htaccess file
* Default: `empty.php`
* The string "-1" disables the test
* __Important:__ path is relative to js file
* __url_getIp__: path to getIP.php or replacement
* Default: `/ip`
* __Important:__ route configured in .htaccess file
* Default: `getIP.php`
* The string "-1" disables the test
* __Important:__ path is relative to js file
* __url_getPointsOfTest__: REST service URL to retrieve the list of available Points of Test
* Default: `/pots`
* Default: `pots.php`
* __url_saveResult__: REST service URL to save test results
* Default: `/save`
* Default: `save.php`
* __url_ispInfo___: Geolocation service and ISP information (http://ipinfo.io/developers#terms-of-use)
* Default: `http://ipinfo.io`
* __enable_quirks__: enables browser-specific optimizations. These optimizations override some of the default settings below. They do not override settings that are explicitly set.

#### Advanced test parameters
* __enable_quirks__: enables browser-specific optimizations. These optimizations override some of the default settings. They do not override settings that are explicitly set.
* Default: `true`
* __enable_multiPots__: enables multiple servers deployment with detection of lowest latency available
* Default: `false`
Expand All @@ -194,15 +203,25 @@ w.postMessage('start {"param1": "value1", "param2": "value2", ...}')
* Default: `3`
* Recommended: `>=1`
* Default override: 1 on Firefox if enable_quirks is true
* Default override: 10 on Safari if enable_quirks is true
* __allow_fetchAPI__: allow the use of Fetch API for the download test instead of regular XHR. Experimental, not recommended.
* Default: `false`
* __force_fetchAPI__: forces the use of Fetch API on all browsers that support it
* Default: `false`
Fetch API are used if the following conditions are met:
* allow_fetchAPI is true
* Chromium-based browser with support for Fetch API and enable_quirks is true
OR force_fetchAPI is true and the browser supports Fetch API
* __xhr_ignoreErrors__: how to react to errors in download/upload streams and the ping test
* `0`: Fail test on error (behaviour of previous versions of this test)
* `1`: Restart a stream/ping when it fails
* `2`: Ignore all errors
* Default: `1`
* Recommended: `1`
* __time_dlGraceTime__: How long to wait (in seconds) before actually measuring the download speed. This is a good idea because we want to wait for the TCP window to be at its maximum (or close to it)
* Default: `1.5`
* Recommended: `>=0`
* __time_ulGraceTime__: How long to wait (in seconds) before actually measuring the upload speed. This is a good idea because we want to wait for the buffers to be full (avoids the peak at the beginning of the test)
* Default: `3`
* Recommended: `>=1`
* __overheadCompensationFactor__: compensation for HTTP and network overhead. Default value assumes typical MTUs used over the Internet. You might want to change this if you're using this in your internal network with different MTUs, or if you're using IPv6 instead of IPv4.
* Default: `1.13359567567567567568` (1048576/925000) assumes HTTP+TCP+IPv4+ETH with typical MTUs used over the Internet
* `1.0513`: HTTP+TCP+IPv6+ETH, over the Internet (empirically tested, not calculated)
* `1.0369`: Alternative value for HTTP+TCP+IPv4+ETH, over the Internet (empirically tested, not calculated)
* `1460 / 1514`: TCP+IPv4+ETH, ignoring HTTP overhead
* `1440 / 1514`: TCP+IPv6+ETH, ignoring HTTP overhead
* `1`: ignore overheads. This measures the speed at which you actually download and upload files

### Aborting the test prematurely
The test can be aborted at any time by sending an abort command to the worker:
Expand All @@ -213,8 +232,24 @@ w.postMessage('abort')

This will terminate all network activity and stop the worker.

__Important:__ do not simply kill the worker while it's running, as it will leave pending XHR requests!
__Important:__ do not simply kill the worker while it's running, as it may leave pending XHR requests!

## Troubleshooting
These are the most common issues reported by users, and how to fix them

#### Download test gives very low result
Are garbage.php and empty.php (or your replacements) reachable?
Press F12, select network and start the test. Do you see errors? (cancelled requests are not errors)
If a small download starts, open it in a text editor. Does it say it's missing openssl_random_pseudo_bytes()? In this case, install OpenSSL (this is usually included when you install Apache and PHP on most distros).

#### Upload test is inaccurate, and I see lag spikes
Check your server's maximum POST size, make sure it's at least 20Mbytes, possibly more

#### All tests are wrong, give extremely high results, browser lags/crashes, ...
You're running the test on localhost, therefore it is trying to measure the speed of your loopback interface. The test is meant to be run over an Internet connection, from a different machine.

#### Ping test shows double the actual ping
Make sure your server is sending the ```Connection:keep-alive``` header

## Using the test without PHP
If your server does not support PHP, or you're using something newer like Node.js, you can still use this test by replacing `garbage.php`, `empty.php` and `getIP.php` with equivalents.
Expand All @@ -231,12 +266,12 @@ It is important here to turn off compression, and generate incompressible data.
A symlink to `/dev/urandom` is also ok.

#### Replacement for `empty.php`
Your replacement must simply respond with a HTTP code 200 and send nothing else. You may want to send additional headers to disable caching.
Your replacement must simply respond with a HTTP code 200 and send nothing else. You may want to send additional headers to disable caching. The test assumes that Connection:keep-alive is sent by the server.

#### Replacement for `getIP.php`
Your replacement must simply respond with the client's IP as plaintext. Nothing fancy.

### JS
#### JS
You need to start the test with your replacements like this:

```js
Expand All @@ -245,10 +280,13 @@ w.postMessage('start {"url_dl": "newGarbageURL", "url_ul": "newEmptyURL", "url_p


## Known bugs and limitations
* The ping/jitter test is measured by seeing how long it takes for an empty XHR to complete. It is not an acutal ICMP ping
* __Chrome:__ high CPU usage from XHR requests with very fast connections (like gigabit).
For this reason, the test may report inaccurate results if your CPU is too slow. (Does not affect most computers)
* __IE11:__ the upload test is not precise on very fast connections
* __IE11:__ the upload test may not work over HTTPS
* __Safari:__ works, but needs more testing and tweaking for very fast connections
* __Firefox:__ on some Linux systems with hardware acceleration turned off, the page rendering makes the browser lag, reducing the accuracy of the ping/jitter test

## Making changes
Since this is an open source project, you can modify it.
Expand All @@ -261,7 +299,7 @@ To create the minified version, use UglifyJS like this:
uglifyjs -c --screw-ie8 speedtest_worker.js > speedtest_worker.min.js
```

Pull requests are much appreciated. If you don't use github (or git), simply contact me.
Pull requests are much appreciated. If you don't use github (or git), simply contact me at [email protected].

__Important:__ please add your name to modified versions to distinguish them from the main project.

Expand Down
4 changes: 2 additions & 2 deletions example6.html
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ <h3>Jitter</h3>
// speedtest cancelled, clear output data
data = []
}
download.textContent = data[1]
upload.textContent = data[2]
download.textContent = (status==1&&data[1]==0)?"Starting":data[1]
upload.textContent = (status==3&&data[2]==0)?"Starting":data[2]
ping.textContent = data[3]
ip.textContent = data[4]
jitter.textContent = data[5]
Expand Down
119 changes: 119 additions & 0 deletions example7.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="referrer" content="no-referrer" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<title>Speedtest</title>

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet" />
<style type="text/css">
.st-block {
text-align: center;
}
.st-btn {
margin-top: -0.5rem;
margin-left: 1.5rem;
}
.st-value>span:empty::before {
content: "0.00";
color: #636c72;
}
#st-ip:empty::before {
content: "___.___.___.___";
color: #636c72;
}
</style>
</head>

<body class="my-4">
<div class="container">
<div class="row">
<div class="col-sm-12 mb-3">
<p class="h1">
Speedtest
<button id="st-start" class="btn btn-outline-primary st-btn" onclick="startTest()">Start</button>
<button id="st-stop" class="btn btn-danger st-btn" onclick="stopTest()" hidden="true">Stop</button>
</p>
<p class="lead">
Your IP: <span id="st-ip"></span>
<input type="checkbox" id="st-ip-checkbox">
</p>
</div>
<div class="col-lg-3 col-md-6 mb-3 st-block">
<h3>Download</h3>
<p class="display-4 st-value"><span id="st-download"></span></p>
<p class="lead">Mbit/s</p>
<p><input type="checkbox" id="st-download-checkbox"></p>
</div>
<div class="col-lg-3 col-md-6 mb-3 st-block">
<h3>Upload</h3>
<p class="display-4 st-value"><span id="st-upload"></span></p>
<p class="lead">Mbit/s</p>
<p><input type="checkbox" id="st-upload-checkbox"></p>
</div>
<div class="col-lg-3 col-md-6 mb-3 st-block">
<h3>Ping</h3>
<p class="display-4 st-value"><span id="st-ping"></span></p>
<p class="lead">ms</p>
<p><input type="checkbox" id="st-ping-checkbox" checked></p>
</div>
<div class="col-lg-3 col-md-6 mb-3 st-block">
<h3>Jitter</h3>
<p class="display-4 st-value"><span id="st-jitter"></span></p>
<p class="lead">ms</p>
</div>
</div>
</div>

<script type="text/javascript">
var worker = null
function startTest() {
document.getElementById('st-start').hidden = true
document.getElementById('st-stop').hidden = false
worker = new Worker('speedtest_worker.min.js')
var interval = setInterval(function () { worker.postMessage('status') }, 100)
worker.onmessage = function (event) {
var download = document.getElementById('st-download')
var upload = document.getElementById('st-upload')
var ping = document.getElementById('st-ping')
var jitter = document.getElementById('st-jitter')
var ip = document.getElementById('st-ip')

var data = event.data.split(';')
var status = Number(data[0])
if (status >= 4) {
clearInterval(interval)
document.getElementById('st-start').hidden = false
document.getElementById('st-stop').hidden = true
w = null
}
if (status === 5) {
// speedtest cancelled, clear output data
data = []
}
download.textContent = (status==1&&data[1]==0)?"Starting":data[1]
upload.textContent = (status==3&&data[2]==0)?"Starting":data[2]
ping.textContent = data[3]
ip.textContent = data[4]
jitter.textContent = data[5]
}
var ip_checkbox = document.getElementById("st-ip-checkbox")
var dl_checkbox = document.getElementById("st-download-checkbox")
var ul_checkbox = document.getElementById("st-upload-checkbox")
var ping_checkbox = document.getElementById("st-ping-checkbox")
var str_parameters = []

if (!ip_checkbox.checked) {str_parameters.push('"url_getIp": "-1"')}
if (!dl_checkbox.checked) {str_parameters.push('"url_dl": "-1"')}
if (!ul_checkbox.checked) {str_parameters.push('"url_ul": "-1"')}
if (!ping_checkbox.checked) {str_parameters.push('"url_ping": "-1"')}

worker.postMessage('start {' + str_parameters.join(",") + '}')
}
function stopTest() {
if (worker) worker.postMessage('abort')
}
</script>
</body>
</html>
Loading

0 comments on commit b495c0e

Please sign in to comment.