dosse91 vor 9 Jahren
Commit
bec767c9ed
5 geänderte Dateien mit 215 neuen und 0 gelöschten Zeilen
  1. 37 0
      README.md
  2. 0 0
      empty.dat
  3. 46 0
      example.html
  4. 9 0
      garbage.php
  5. 123 0
      speedtest.js

+ 37 - 0
README.md

@@ -0,0 +1,37 @@
+# Speedtest in 4k
+
+No Flash, No Java, No Websocket, No Bullshit.
+
+This is a very small (4k) Speedtest implemented in Javascript, that relies only on XMLHttpRequest.
+
+## Try it
+[Take a Speedtest](http://speedtest.adolfintel.com)
+
+## Compatibility
+Microsoft Edge, Firefox 10+, Chrome 10+, Opera 15+, Safari 7 (not tested)
+
+## Requirements
+ - A reasonably fast web serve
+ - Some way to generate garbage data using either the included PHP script, a [big file of random data](http://downloads.adolfintel.com/geth.php?r=speedtest-bigfile), or a symlink to /dev/urandom
+ - Your server must not compress the data it sends
+ - Your server must accept large POST requests (up to 10 Megabytes), otherwise the upload test will fail
+ - Client side, there must not be any type of buffering (such as a proxy), or you may get incorrect results
+
+## How to use
+See example.html, it's not rocket science.
+
+## License
+Copyright (C) 2016 Federico Dossena
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/lgpl>.

+ 0 - 0
empty.dat


+ 46 - 0
example.html

@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Speedtest</title>
+<script type="text/javascript" src="speedtest.js"></script>
+</head>
+<body>
+<h1>Speedtest</h1>
+<h4>Download</h4>
+<div id="download">Wait...</div>
+<h4>Upload</h4>
+<div id="upload">Wait...</div>
+<h4>Latency</h4>
+<div id="ping">Wait...</div>
+<script type="text/javascript">
+	var tester=new DownloadTester("garbage.php");
+	var d=document.getElementById("download");
+	tester.onUpdate=function(){
+		d.innerHTML=tester.getValue()+" Megabit/s";
+	}
+	tester.onFail=function(){
+		d.innerHTML="Failed";
+		tester.onDone();
+	}
+	tester.onDone=function(){
+		tester=new UploadTester("upload-test");
+		d=document.getElementById("upload");
+		tester.onUpdate=function(){
+			d.innerHTML=tester.getValue()+" Megabit/s";
+		}
+		tester.onFail=function(){
+			d.innerHTML="Failed";
+			tester.onDone();
+		}
+		tester.onDone=function(){
+			tester=new PingTester("empty.dat");
+			d=document.getElementById("ping");
+			tester.onUpdate=function(){
+				d.innerHTML=tester.getValue()+" ms";
+			}
+			tester.onFail=function(){d.innerHTML="Failed";}
+		}
+	}
+</script>
+</body>
+</html>

+ 9 - 0
garbage.php

@@ -0,0 +1,9 @@
+<?php
+header( "HTTP/1.1 200 OK" );
+$data=str_repeat("0",1048576);
+while(1){
+	echo $data;
+	flush();
+}
+
+?>

+ 123 - 0
speedtest.js

@@ -0,0 +1,123 @@
+function DownloadTester(serverURL,done,update,err){
+	this.xhr=new XMLHttpRequest();
+	this.firstTick=true;
+	this.prevLoaded=0;
+	this.startT=new Date().getTime();
+	this.prevT=new Date().getTime();
+	this.speed=0.0;
+	if(done)this.onDone=done; if(update)this.onUpdate=update; if(err)this.onFail=err;
+	this.xhr.onprogress=function(event){
+		var instspd=(event.loaded-this.prevLoaded)/((new Date().getTime()-this.prevT)/1000.0);
+		if(isNaN(instspd)||!isFinite(instspd)) return;
+		if(this.firstTick){
+			this.speed=instspd;
+			this.firstTick=false;
+		}else{
+			this.speed=this.speed*0.9+instspd*0.1;
+		}
+		this.prevLoaded=event.loaded;
+		this.prevT=new Date().getTime();
+		this.onUpdate();
+		if(((this.prevT-this.startT)/1000.0)>15){try{this.xhr.abort();}catch(e){} this.onDone();}
+	}.bind(this);
+	this.xhr.onload=function(){
+		this.onUpdate();
+		this.onDone();
+	}.bind(this);
+	this.xhr.onerror=function(){
+		this.onUpdate();
+		this.onFail();
+	}.bind(this);
+	this.xhr.open("GET", serverURL+"?random="+Math.random(),true);
+	this.xhr.send();
+}
+DownloadTester.prototype={
+	constructor:DownloadTester,
+	onDone:function(){},
+	onFail:function(){},
+	onUpdate:function(){},
+	getValue:function(){return ((this.speed*8)/1048576.0).toFixed(2);},
+	cancel:function(){try{this.xhr.abort();}catch(e){}}
+}
+
+function UploadTester(serverURL,done,update,err){
+	this.xhr=new XMLHttpRequest();
+	this.firstTick=true;
+	this.prevLoaded=0;
+	this.startT=new Date().getTime();
+	this.prevT=new Date().getTime();
+	this.speed=0.0;
+	if(done)this.onDone=done; if(update)this.onUpdate=update; if(err)this.onFail=err;
+	this.xhr.upload.onprogress=function(event){
+		var instspd=(event.loaded-this.prevLoaded)/((new Date().getTime()-this.prevT)/1000.0);
+		if(isNaN(instspd)||!isFinite(instspd)) return;
+		if(this.firstTick){
+			this.firstTick=false;
+		}else{
+			this.speed=this.speed*0.7+instspd*0.3;
+		}
+		this.prevLoaded=event.loaded;
+		this.prevT=new Date().getTime();
+		this.onUpdate();
+		if(((this.prevT-this.startT)/1000.0)>15){try{this.xhr.abort();}catch(e){} this.onDone();}
+	}.bind(this);
+	this.xhr.onload=function(){
+		this.onUpdate();
+		this.onDone();
+	}.bind(this);
+	this.xhr.onerror=function(){
+		this.onUpdate();
+		this.onFail();
+	}.bind(this);
+	this.xhr.open("POST", serverURL+"?random="+Math.random(),true);
+	this.xhr.send(new ArrayBuffer(10485760));
+}
+UploadTester.prototype={
+	constructor:UploadTester,
+	onDone:function(){},
+	onFail:function(){},
+	onUpdate:function(){},
+	getValue:function(){return ((this.speed*8)/1048576.0).toFixed(2);},
+	cancel:function(){try{this.xhr.abort();}catch(e){}}
+}
+
+function PingTester(serverURL,done,update,err){
+	this.xhr=null;
+	this.prevT=null;
+	this.ping=0.0;
+	this.i=0;
+	this.pingURL=serverURL;
+	if(done)this.onDone=done;
+	if(update)this.onUpdate=update;
+	if(err)this.onFail=err;
+	this.doPing=function(){
+		this.prevT=new Date().getTime();
+		this.xhr=new XMLHttpRequest();
+		this.xhr.onload=function(){
+			if(this.i==0){
+				this.prevT=new Date().getTime();
+			}else{
+				var instspd=new Date().getTime()-this.prevT;
+				if(this.i==1) this.ping=instspd; else this.ping=this.ping*0.9+instspd*0.1;
+			}
+			this.onUpdate();
+			this.i++;
+			if(this.i<50) this.doPing(); else this.onDone();
+		}.bind(this);
+		this.xhr.onerror=function(){
+			this.onUpdate();
+			this.onFail();
+		}.bind(this);
+		this.xhr.open("GET", this.pingURL+"?random="+Math.random(),true);
+		this.xhr.send();
+	}.bind(this);
+	this.doPing();
+}
+PingTester.prototype={
+	constructor:PingTester,
+	onDone:function(){},
+	onFail:function(){},
+	onUpdate:function(){},
+	getValue:function(){return this.ping.toFixed(2);},
+	cancel:function(){this.i=9999; if(this.xhr) try{xhr.abort();}catch(e){}}
+}