mirror of
https://github.com/servo/servo.git
synced 2025-08-10 16:05:43 +01:00
Update web-platform-tests to revision e92532746b7615dcccdfa060937a87664816b1db
This commit is contained in:
parent
cccca27f4f
commit
726b56aa12
149 changed files with 22796 additions and 1884 deletions
|
@ -0,0 +1,43 @@
|
|||
# Copyright 2012, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
from mod_pywebsocket import handshake
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
raise handshake.AbortedByUserException(
|
||||
"Aborted in web_socket_do_extra_handshake")
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
pass
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,43 @@
|
|||
# Copyright 2012, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
from mod_pywebsocket import handshake
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
pass
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
raise handshake.AbortedByUserException(
|
||||
"Aborted in web_socket_transfer_data")
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,134 @@
|
|||
<!--
|
||||
Copyright 2013, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>ArrayBuffer benchmark</title>
|
||||
<script src="util.js"></script>
|
||||
<script>
|
||||
var PRINT_SIZE = true;
|
||||
|
||||
// Initial size of arrays.
|
||||
var START_SIZE = 10 * 1024;
|
||||
// Stops benchmark when the size of an array exceeds this threshold.
|
||||
var STOP_THRESHOLD = 100000 * 1024;
|
||||
// If the size of each array is small, write/read the array multiple times
|
||||
// until the sum of sizes reaches this threshold.
|
||||
var MIN_TOTAL = 100000 * 1024;
|
||||
var MULTIPLIERS = [5, 2];
|
||||
|
||||
// Repeat benchmark for several times to measure performance of optimized
|
||||
// (such as JIT) run.
|
||||
var REPEAT_FOR_WARMUP = 3;
|
||||
|
||||
function writeBenchmark(size, minTotal) {
|
||||
var totalSize = 0;
|
||||
while (totalSize < minTotal) {
|
||||
var arrayBuffer = new ArrayBuffer(size);
|
||||
|
||||
// Write 'a's.
|
||||
fillArrayBuffer(arrayBuffer, 0x61);
|
||||
|
||||
totalSize += size;
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
function readBenchmark(size, minTotal) {
|
||||
var totalSize = 0;
|
||||
while (totalSize < minTotal) {
|
||||
var arrayBuffer = new ArrayBuffer(size);
|
||||
|
||||
if (!verifyArrayBuffer(arrayBuffer, 0x00)) {
|
||||
queueLog('Verification failed');
|
||||
return -1;
|
||||
}
|
||||
|
||||
totalSize += size;
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
function runBenchmark(benchmarkFunction,
|
||||
size,
|
||||
stopThreshold,
|
||||
minTotal,
|
||||
multipliers,
|
||||
multiplierIndex) {
|
||||
while (size <= stopThreshold) {
|
||||
var maxSpeed = 0;
|
||||
|
||||
for (var i = 0; i < REPEAT_FOR_WARMUP; ++i) {
|
||||
var startTimeInMs = getTimeStamp();
|
||||
|
||||
var totalSize = benchmarkFunction(size, minTotal);
|
||||
|
||||
maxSpeed = Math.max(maxSpeed,
|
||||
calculateSpeedInKB(totalSize, startTimeInMs));
|
||||
}
|
||||
queueLog(formatResultInKiB(size, maxSpeed, PRINT_SIZE));
|
||||
|
||||
size *= multipliers[multiplierIndex];
|
||||
multiplierIndex = (multiplierIndex + 1) % multipliers.length;
|
||||
}
|
||||
}
|
||||
|
||||
function runBenchmarks() {
|
||||
queueLog('Message size in KiB, Speed in kB/s');
|
||||
|
||||
queueLog('Write benchmark');
|
||||
runBenchmark(
|
||||
writeBenchmark, START_SIZE, STOP_THRESHOLD, MIN_TOTAL, MULTIPLIERS, 0);
|
||||
queueLog('Finished');
|
||||
|
||||
queueLog('Read benchmark');
|
||||
runBenchmark(
|
||||
readBenchmark, START_SIZE, STOP_THRESHOLD, MIN_TOTAL, MULTIPLIERS, 0);
|
||||
addToLog('Finished');
|
||||
}
|
||||
|
||||
function init() {
|
||||
logBox = document.getElementById('log');
|
||||
|
||||
queueLog(window.navigator.userAgent.toLowerCase());
|
||||
|
||||
addToLog('Started...');
|
||||
|
||||
setTimeout(runBenchmarks, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<textarea
|
||||
id="log" rows="50" style="width: 100%" readonly></textarea>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright 2011, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
"""A simple load tester for WebSocket clients.
|
||||
|
||||
A client program sends a message formatted as "<time> <count> <message>" to
|
||||
this handler. This handler starts sending total <count> WebSocket messages
|
||||
containing <message> every <time> seconds. <time> can be a floating point
|
||||
value. <count> must be an integer value.
|
||||
"""
|
||||
|
||||
|
||||
import time
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
pass # Always accept.
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
line = request.ws_stream.receive_message()
|
||||
parts = line.split(' ')
|
||||
if len(parts) != 3:
|
||||
raise ValueError('Bad parameter format')
|
||||
wait = float(parts[0])
|
||||
count = int(parts[1])
|
||||
message = parts[2]
|
||||
for i in xrange(count):
|
||||
request.ws_stream.send_message(message)
|
||||
time.sleep(wait)
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,175 @@
|
|||
<!--
|
||||
Copyright 2013, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>WebSocket benchmark</title>
|
||||
<script src="util_main.js"></script>
|
||||
<script src="util.js"></script>
|
||||
<script src="benchmark.js"></script>
|
||||
<script>
|
||||
var addressBox = null;
|
||||
|
||||
function getConfig() {
|
||||
return {
|
||||
prefixUrl: addressBox.value,
|
||||
printSize: getBoolFromCheckBox('printsize'),
|
||||
numSockets: getIntFromInput('numsockets'),
|
||||
// Initial size of messages.
|
||||
numIterations: getIntFromInput('numiterations'),
|
||||
numWarmUpIterations: getIntFromInput('numwarmupiterations'),
|
||||
startSize: getIntFromInput('startsize'),
|
||||
// Stops benchmark when the size of message exceeds this threshold.
|
||||
stopThreshold: getIntFromInput('stopthreshold'),
|
||||
// If the size of each message is small, send/receive multiple messages
|
||||
// until the sum of sizes reaches this threshold.
|
||||
minTotal: getIntFromInput('mintotal'),
|
||||
multipliers: getFloatArrayFromInput('multipliers'),
|
||||
verifyData: getBoolFromCheckBox('verifydata'),
|
||||
addToLog: addToLog,
|
||||
addToSummary: addToSummary,
|
||||
measureValue: measureValue,
|
||||
notifyAbort: notifyAbort
|
||||
};
|
||||
}
|
||||
|
||||
function onSendBenchmark() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'sendBenchmark');
|
||||
}
|
||||
|
||||
function onReceiveBenchmark() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'receiveBenchmark');
|
||||
}
|
||||
|
||||
function onBatchBenchmark() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'batchBenchmark');
|
||||
}
|
||||
|
||||
function onStop() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'stop');
|
||||
}
|
||||
|
||||
function init() {
|
||||
addressBox = document.getElementById('address');
|
||||
logBox = document.getElementById('log');
|
||||
|
||||
summaryBox = document.getElementById('summary');
|
||||
|
||||
var scheme = window.location.protocol == 'https:' ? 'wss://' : 'ws://';
|
||||
var defaultAddress = scheme + window.location.host + '/benchmark_helper';
|
||||
|
||||
addressBox.value = defaultAddress;
|
||||
|
||||
addToLog(window.navigator.userAgent.toLowerCase());
|
||||
addToSummary(window.navigator.userAgent.toLowerCase());
|
||||
|
||||
if (!('WebSocket' in window)) {
|
||||
addToLog('WebSocket is not available');
|
||||
}
|
||||
|
||||
initWorker('WebSocket', '');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
|
||||
<div id="benchmark_div">
|
||||
url <input type="text" id="address" size="40">
|
||||
<input type="button" value="send" onclick="onSendBenchmark()">
|
||||
<input type="button" value="receive" onclick="onReceiveBenchmark()">
|
||||
<input type="button" value="batch" onclick="onBatchBenchmark()">
|
||||
<input type="button" value="stop" onclick="onStop()">
|
||||
|
||||
<br/>
|
||||
|
||||
<input type="checkbox" id="printsize" checked>
|
||||
<label for="printsize">Print size and time per message</label>
|
||||
<input type="checkbox" id="verifydata" checked>
|
||||
<label for="verifydata">Verify data</label>
|
||||
<input type="checkbox" id="worker">
|
||||
<label for="worker">Run on worker</label>
|
||||
|
||||
<br/>
|
||||
|
||||
Parameters:
|
||||
|
||||
<br/>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Num sockets</td>
|
||||
<td><input type="text" id="numsockets" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of iterations</td>
|
||||
<td><input type="text" id="numiterations" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of warm-up iterations</td>
|
||||
<td><input type="text" id="numwarmupiterations" value="0"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start size</td>
|
||||
<td><input type="text" id="startsize" value="10240"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stop threshold</td>
|
||||
<td><input type="text" id="stopthreshold" value="102400000"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Minimum total</td>
|
||||
<td><input type="text" id="mintotal" value="102400000"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multipliers</td>
|
||||
<td><input type="text" id="multipliers" value="5, 2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="log_div">
|
||||
<textarea
|
||||
id="log" rows="20" style="width: 100%" readonly></textarea>
|
||||
</div>
|
||||
<div id="summary_div">
|
||||
Summary
|
||||
<textarea
|
||||
id="summary" rows="20" style="width: 100%" readonly></textarea>
|
||||
</div>
|
||||
|
||||
Note: Effect of RTT is not eliminated.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,214 @@
|
|||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the COPYING file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
if (typeof importScripts !== "undefined") {
|
||||
// Running on a worker
|
||||
importScripts('util.js', 'util_worker.js');
|
||||
}
|
||||
|
||||
// Namespace for holding globals.
|
||||
var benchmark = {startTimeInMs: 0};
|
||||
|
||||
var sockets = [];
|
||||
var numEstablishedSockets = 0;
|
||||
|
||||
var timerID = null;
|
||||
|
||||
function destroySocket(socket) {
|
||||
socket.onopen = null;
|
||||
socket.onmessage = null;
|
||||
socket.onerror = null;
|
||||
socket.onclose = null;
|
||||
socket.close();
|
||||
}
|
||||
|
||||
function destroyAllSockets() {
|
||||
for (var i = 0; i < sockets.length; ++i) {
|
||||
destroySocket(sockets[i]);
|
||||
}
|
||||
sockets = [];
|
||||
}
|
||||
|
||||
function sendBenchmarkStep(size, config, isWarmUp) {
|
||||
timerID = null;
|
||||
|
||||
var totalSize = 0;
|
||||
var totalReplied = 0;
|
||||
|
||||
var onMessageHandler = function(event) {
|
||||
if (!verifyAcknowledgement(config, event.data, size)) {
|
||||
destroyAllSockets();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
totalReplied += size;
|
||||
|
||||
if (totalReplied < totalSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize,
|
||||
isWarmUp);
|
||||
|
||||
runNextTask(config);
|
||||
};
|
||||
|
||||
for (var i = 0; i < sockets.length; ++i) {
|
||||
var socket = sockets[i];
|
||||
socket.onmessage = onMessageHandler;
|
||||
}
|
||||
|
||||
var dataArray = [];
|
||||
|
||||
while (totalSize < config.minTotal) {
|
||||
var buffer = new ArrayBuffer(size);
|
||||
|
||||
fillArrayBuffer(buffer, 0x61);
|
||||
|
||||
dataArray.push(buffer);
|
||||
totalSize += size;
|
||||
}
|
||||
|
||||
benchmark.startTimeInMs = getTimeStamp();
|
||||
|
||||
totalSize = 0;
|
||||
|
||||
var socketIndex = 0;
|
||||
var dataIndex = 0;
|
||||
while (totalSize < config.minTotal) {
|
||||
var command = ['send'];
|
||||
command.push(config.verifyData ? '1' : '0');
|
||||
sockets[socketIndex].send(command.join(' '));
|
||||
sockets[socketIndex].send(dataArray[dataIndex]);
|
||||
socketIndex = (socketIndex + 1) % sockets.length;
|
||||
|
||||
totalSize += size;
|
||||
++dataIndex;
|
||||
}
|
||||
}
|
||||
|
||||
function receiveBenchmarkStep(size, config, isWarmUp) {
|
||||
timerID = null;
|
||||
|
||||
var totalSize = 0;
|
||||
var totalReplied = 0;
|
||||
|
||||
var onMessageHandler = function(event) {
|
||||
var bytesReceived = event.data.byteLength;
|
||||
if (bytesReceived != size) {
|
||||
config.addToLog('Expected ' + size + 'B but received ' +
|
||||
bytesReceived + 'B');
|
||||
destroyAllSockets();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.verifyData && !verifyArrayBuffer(event.data, 0x61)) {
|
||||
config.addToLog('Response verification failed');
|
||||
destroyAllSockets();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
totalReplied += bytesReceived;
|
||||
|
||||
if (totalReplied < totalSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize,
|
||||
isWarmUp);
|
||||
|
||||
runNextTask(config);
|
||||
};
|
||||
|
||||
for (var i = 0; i < sockets.length; ++i) {
|
||||
var socket = sockets[i];
|
||||
socket.binaryType = 'arraybuffer';
|
||||
socket.onmessage = onMessageHandler;
|
||||
}
|
||||
|
||||
benchmark.startTimeInMs = getTimeStamp();
|
||||
|
||||
var socketIndex = 0;
|
||||
while (totalSize < config.minTotal) {
|
||||
sockets[socketIndex].send('receive ' + size);
|
||||
socketIndex = (socketIndex + 1) % sockets.length;
|
||||
|
||||
totalSize += size;
|
||||
}
|
||||
}
|
||||
|
||||
function createSocket(config) {
|
||||
// TODO(tyoshino): Add TCP warm up.
|
||||
var url = config.prefixUrl;
|
||||
|
||||
config.addToLog('Connect ' + url);
|
||||
|
||||
var socket = new WebSocket(url);
|
||||
socket.onmessage = function(event) {
|
||||
config.addToLog('Unexpected message received. Aborting.');
|
||||
};
|
||||
socket.onerror = function() {
|
||||
config.addToLog('Error');
|
||||
};
|
||||
socket.onclose = function(event) {
|
||||
config.addToLog('Closed');
|
||||
config.notifyAbort();
|
||||
};
|
||||
return socket;
|
||||
}
|
||||
|
||||
function startBenchmark(config) {
|
||||
clearTimeout(timerID);
|
||||
destroyAllSockets();
|
||||
|
||||
numEstablishedSockets = 0;
|
||||
|
||||
for (var i = 0; i < config.numSockets; ++i) {
|
||||
var socket = createSocket(config);
|
||||
socket.onopen = function() {
|
||||
config.addToLog('Opened');
|
||||
|
||||
++numEstablishedSockets;
|
||||
|
||||
if (numEstablishedSockets == sockets.length) {
|
||||
runNextTask(config);
|
||||
}
|
||||
};
|
||||
sockets.push(socket);
|
||||
}
|
||||
}
|
||||
|
||||
function getConfigString(config) {
|
||||
return '(WebSocket' +
|
||||
', ' + (typeof importScripts !== "undefined" ? 'Worker' : 'Main') +
|
||||
', numSockets=' + config.numSockets +
|
||||
', numIterations=' + config.numIterations +
|
||||
', verifyData=' + config.verifyData +
|
||||
', minTotal=' + config.minTotal +
|
||||
', numWarmUpIterations=' + config.numWarmUpIterations +
|
||||
')';
|
||||
}
|
||||
|
||||
function batchBenchmark(config) {
|
||||
config.addToLog('Batch benchmark');
|
||||
config.addToLog(buildLegendString(config));
|
||||
|
||||
tasks = [];
|
||||
clearAverageData();
|
||||
addTasks(config, sendBenchmarkStep);
|
||||
addResultReportingTask(config, 'Send Benchmark ' + getConfigString(config));
|
||||
addTasks(config, receiveBenchmarkStep);
|
||||
addResultReportingTask(config, 'Receive Benchmark ' +
|
||||
getConfigString(config));
|
||||
startBenchmark(config);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
destroyAllSockets();
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
# Copyright 2013, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
"""Handler for benchmark.html."""
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
# Turn off compression.
|
||||
request.ws_extension_processors = []
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
data = ''
|
||||
|
||||
while True:
|
||||
command = request.ws_stream.receive_message()
|
||||
if command is None:
|
||||
return
|
||||
|
||||
if not isinstance(command, unicode):
|
||||
raise ValueError('Invalid command data:' + command)
|
||||
commands = command.split(' ')
|
||||
if len(commands) == 0:
|
||||
raise ValueError('Invalid command data: ' + command)
|
||||
|
||||
if commands[0] == 'receive':
|
||||
if len(commands) != 2:
|
||||
raise ValueError(
|
||||
'Illegal number of arguments for send command' +
|
||||
command)
|
||||
size = int(commands[1])
|
||||
|
||||
# Reuse data if possible.
|
||||
if len(data) != size:
|
||||
data = 'a' * size
|
||||
request.ws_stream.send_message(data, binary=True)
|
||||
elif commands[0] == 'send':
|
||||
if len(commands) != 2:
|
||||
raise ValueError(
|
||||
'Illegal number of arguments for receive command' +
|
||||
command)
|
||||
verify_data = commands[1] == '1'
|
||||
|
||||
data = request.ws_stream.receive_message()
|
||||
if data is None:
|
||||
raise ValueError('Payload not received')
|
||||
size = len(data)
|
||||
|
||||
if verify_data:
|
||||
if data != 'a' * size:
|
||||
raise ValueError('Payload verification failed')
|
||||
|
||||
request.ws_stream.send_message(str(size))
|
||||
else:
|
||||
raise ValueError('Invalid command: ' + commands[0])
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,69 @@
|
|||
# Copyright 2012, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import struct
|
||||
|
||||
from mod_pywebsocket import common
|
||||
from mod_pywebsocket import stream
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
pass
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
while True:
|
||||
line = request.ws_stream.receive_message()
|
||||
if line is None:
|
||||
return
|
||||
code, reason = line.split(' ', 1)
|
||||
if code is None or reason is None:
|
||||
return
|
||||
request.ws_stream.close_connection(int(code), reason)
|
||||
# close_connection() initiates closing handshake. It validates code
|
||||
# and reason. If you want to send a broken close frame for a test,
|
||||
# following code will be useful.
|
||||
# > data = struct.pack('!H', int(code)) + reason.encode('UTF-8')
|
||||
# > request.connection.write(stream.create_close_frame(data))
|
||||
# > # Suppress to re-respond client responding close frame.
|
||||
# > raise Exception("customized server initiated closing handshake")
|
||||
|
||||
|
||||
def web_socket_passive_closing_handshake(request):
|
||||
# Simply echo a close status code
|
||||
code, reason = request.ws_close_code, request.ws_close_reason
|
||||
|
||||
# pywebsocket sets pseudo code for receiving an empty body close frame.
|
||||
if code == common.STATUS_NO_STATUS_RECEIVED:
|
||||
code = None
|
||||
reason = ''
|
||||
return code, reason
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,317 @@
|
|||
<!--
|
||||
Copyright 2011, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<!--
|
||||
A simple console for testing WebSocket server.
|
||||
|
||||
Type an address into the top text input and click connect to establish
|
||||
WebSocket. Then, type some message into the bottom text input and click send
|
||||
to send the message. Received/sent messages and connection state will be shown
|
||||
on the middle textarea.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>WebSocket console</title>
|
||||
<script>
|
||||
var socket = null;
|
||||
|
||||
var showTimeStamp = false;
|
||||
|
||||
var addressBox = null;
|
||||
var protocolsBox = null;
|
||||
var logBox = null;
|
||||
var messageBox = null;
|
||||
var fileBox = null;
|
||||
var codeBox = null;
|
||||
var reasonBox = null;
|
||||
|
||||
function getTimeStamp() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
|
||||
function addToLog(log) {
|
||||
if (showTimeStamp) {
|
||||
logBox.value += '[' + getTimeStamp() + '] ';
|
||||
}
|
||||
logBox.value += log + '\n'
|
||||
// Large enough to keep showing the latest message.
|
||||
logBox.scrollTop = 1000000;
|
||||
}
|
||||
|
||||
function setbinarytype(binaryType) {
|
||||
if (!socket) {
|
||||
addToLog('Not connected');
|
||||
return;
|
||||
}
|
||||
|
||||
socket.binaryType = binaryType;
|
||||
addToLog('Set binaryType to ' + binaryType);
|
||||
}
|
||||
|
||||
function send() {
|
||||
if (!socket) {
|
||||
addToLog('Not connected');
|
||||
return;
|
||||
}
|
||||
|
||||
socket.send(messageBox.value);
|
||||
addToLog('> ' + messageBox.value);
|
||||
messageBox.value = '';
|
||||
}
|
||||
|
||||
function sendfile() {
|
||||
if (!socket) {
|
||||
addToLog('Not connected');
|
||||
return;
|
||||
}
|
||||
|
||||
var files = fileBox.files;
|
||||
|
||||
if (files.length == 0) {
|
||||
addToLog('File not selected');
|
||||
return;
|
||||
}
|
||||
|
||||
socket.send(files[0]);
|
||||
addToLog('> Send ' + files[0].name);
|
||||
}
|
||||
|
||||
function parseProtocols(protocolsText) {
|
||||
var protocols = protocolsText.split(',');
|
||||
for (var i = 0; i < protocols.length; ++i) {
|
||||
protocols[i] = protocols[i].trim();
|
||||
}
|
||||
|
||||
if (protocols.length == 0) {
|
||||
// Don't pass.
|
||||
protocols = null;
|
||||
} else if (protocols.length == 1) {
|
||||
if (protocols[0].length == 0) {
|
||||
// Don't pass.
|
||||
protocols = null;
|
||||
} else {
|
||||
// Pass as a string.
|
||||
protocols = protocols[0];
|
||||
}
|
||||
}
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
function connect() {
|
||||
var url = addressBox.value;
|
||||
var protocols = parseProtocols(protocolsBox.value);
|
||||
|
||||
if ('WebSocket' in window) {
|
||||
if (protocols) {
|
||||
socket = new WebSocket(url, protocols);
|
||||
} else {
|
||||
socket = new WebSocket(url);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
socket.onopen = function () {
|
||||
var extraInfo = [];
|
||||
if (('protocol' in socket) && socket.protocol) {
|
||||
extraInfo.push('protocol = ' + socket.protocol);
|
||||
}
|
||||
if (('extensions' in socket) && socket.extensions) {
|
||||
extraInfo.push('extensions = ' + socket.extensions);
|
||||
}
|
||||
|
||||
var logMessage = 'Opened';
|
||||
if (extraInfo.length > 0) {
|
||||
logMessage += ' (' + extraInfo.join(', ') + ')';
|
||||
}
|
||||
addToLog(logMessage);
|
||||
};
|
||||
socket.onmessage = function (event) {
|
||||
if (('ArrayBuffer' in window) && (event.data instanceof ArrayBuffer)) {
|
||||
addToLog('< Received an ArrayBuffer of ' + event.data.byteLength +
|
||||
' bytes')
|
||||
} else if (('Blob' in window) && (event.data instanceof Blob)) {
|
||||
addToLog('< Received a Blob of ' + event.data.size + ' bytes')
|
||||
} else {
|
||||
addToLog('< ' + event.data);
|
||||
}
|
||||
};
|
||||
socket.onerror = function () {
|
||||
addToLog('Error');
|
||||
};
|
||||
socket.onclose = function (event) {
|
||||
var logMessage = 'Closed (';
|
||||
if ((arguments.length == 1) && ('CloseEvent' in window) &&
|
||||
(event instanceof CloseEvent)) {
|
||||
logMessage += 'wasClean = ' + event.wasClean;
|
||||
// code and reason are present only for
|
||||
// draft-ietf-hybi-thewebsocketprotocol-06 and later
|
||||
if ('code' in event) {
|
||||
logMessage += ', code = ' + event.code;
|
||||
}
|
||||
if ('reason' in event) {
|
||||
logMessage += ', reason = ' + event.reason;
|
||||
}
|
||||
} else {
|
||||
logMessage += 'CloseEvent is not available';
|
||||
}
|
||||
addToLog(logMessage + ')');
|
||||
};
|
||||
|
||||
if (protocols) {
|
||||
addToLog('Connect ' + url + ' (protocols = ' + protocols + ')');
|
||||
} else {
|
||||
addToLog('Connect ' + url);
|
||||
}
|
||||
}
|
||||
|
||||
function closeSocket() {
|
||||
if (!socket) {
|
||||
addToLog('Not connected');
|
||||
return;
|
||||
}
|
||||
|
||||
if (codeBox.value || reasonBox.value) {
|
||||
socket.close(codeBox.value, reasonBox.value);
|
||||
} else {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
function printState() {
|
||||
if (!socket) {
|
||||
addToLog('Not connected');
|
||||
return;
|
||||
}
|
||||
|
||||
addToLog(
|
||||
'url = ' + socket.url +
|
||||
', readyState = ' + socket.readyState +
|
||||
', bufferedAmount = ' + socket.bufferedAmount);
|
||||
}
|
||||
|
||||
function init() {
|
||||
var scheme = window.location.protocol == 'https:' ? 'wss://' : 'ws://';
|
||||
var defaultAddress = scheme + window.location.host + '/echo';
|
||||
|
||||
addressBox = document.getElementById('address');
|
||||
protocolsBox = document.getElementById('protocols');
|
||||
logBox = document.getElementById('log');
|
||||
messageBox = document.getElementById('message');
|
||||
fileBox = document.getElementById('file');
|
||||
codeBox = document.getElementById('code');
|
||||
reasonBox = document.getElementById('reason');
|
||||
|
||||
addressBox.value = defaultAddress;
|
||||
|
||||
if (!('WebSocket' in window)) {
|
||||
addToLog('WebSocket is not available');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
form {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#connect_div, #log_div, #send_div, #sendfile_div, #close_div, #printstate_div {
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
border-width: 0px 0px 0px 10px;
|
||||
border-style: solid;
|
||||
border-color: silver;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
|
||||
<div>
|
||||
|
||||
<div id="connect_div">
|
||||
<form action="#" onsubmit="connect(); return false;">
|
||||
url <input type="text" id="address" size="40">
|
||||
<input type="submit" value="connect">
|
||||
<br/>
|
||||
protocols <input type="text" id="protocols" size="20">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="log_div">
|
||||
<textarea id="log" rows="10" cols="40" readonly></textarea>
|
||||
<br/>
|
||||
<input type="checkbox"
|
||||
name="showtimestamp"
|
||||
value="showtimestamp"
|
||||
onclick="showTimeStamp = this.checked">Show time stamp
|
||||
</div>
|
||||
|
||||
<div id="send_div">
|
||||
<form action="#" onsubmit="send(); return false;">
|
||||
data <input type="text" id="message" size="40">
|
||||
<input type="submit" value="send">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="sendfile_div">
|
||||
<form action="#" onsubmit="sendfile(); return false;">
|
||||
<input type="file" id="file" size="40">
|
||||
<input type="submit" value="send file">
|
||||
</form>
|
||||
|
||||
Set binaryType
|
||||
<input type="radio"
|
||||
name="binarytype"
|
||||
value="blob"
|
||||
onclick="setbinarytype('blob')" checked>blob
|
||||
<input type="radio"
|
||||
name="binarytype"
|
||||
value="arraybuffer"
|
||||
onclick="setbinarytype('arraybuffer')">arraybuffer
|
||||
</div>
|
||||
|
||||
<div id="close_div">
|
||||
<form action="#" onsubmit="closeSocket(); return false;">
|
||||
code <input type="text" id="code" size="10">
|
||||
reason <input type="text" id="reason" size="20">
|
||||
<input type="submit" value="close">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="printstate_div">
|
||||
<input type="button" value="print state" onclick="printState();">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,32 @@
|
|||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the COPYING file or at
|
||||
# https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
|
||||
import urlparse
|
||||
|
||||
|
||||
def _add_set_cookie(request, value):
|
||||
request.extra_headers.append(('Set-Cookie', value))
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
components = urlparse.urlparse(request.uri)
|
||||
command = components[4]
|
||||
|
||||
ONE_DAY_LIFE = 'Max-Age=86400'
|
||||
|
||||
if command == 'set':
|
||||
_add_set_cookie(request, '; '.join(['foo=bar', ONE_DAY_LIFE]))
|
||||
elif command == 'set_httponly':
|
||||
_add_set_cookie(request,
|
||||
'; '.join(['httpOnlyFoo=bar', ONE_DAY_LIFE, 'httpOnly']))
|
||||
elif command == 'clear':
|
||||
_add_set_cookie(request, 'foo=0; Max-Age=0')
|
||||
_add_set_cookie(request, 'httpOnlyFoo=0; Max-Age=0')
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
pass
|
1128
tests/wpt/web-platform-tests/tools/pywebsocket/example/echo_client.py
Executable file
1128
tests/wpt/web-platform-tests/tools/pywebsocket/example/echo_client.py
Executable file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,61 @@
|
|||
# Copyright 2013, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
_GOODBYE_MESSAGE = u'Goodbye'
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
"""Received Sec-WebSocket-Extensions header value is parsed into
|
||||
request.ws_requested_extensions. pywebsocket creates extension
|
||||
processors using it before do_extra_handshake call and never looks at it
|
||||
after the call.
|
||||
|
||||
To reject requested extensions, clear the processor list.
|
||||
"""
|
||||
|
||||
request.ws_extension_processors = []
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
"""Echo. Same as echo_wsh.py."""
|
||||
|
||||
while True:
|
||||
line = request.ws_stream.receive_message()
|
||||
if line is None:
|
||||
return
|
||||
if isinstance(line, unicode):
|
||||
request.ws_stream.send_message(line, binary=False)
|
||||
if line == _GOODBYE_MESSAGE:
|
||||
return
|
||||
else:
|
||||
request.ws_stream.send_message(line, binary=True)
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,54 @@
|
|||
# Copyright 2011, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
_GOODBYE_MESSAGE = u'Goodbye'
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
# This example handler accepts any request. See origin_check_wsh.py for how
|
||||
# to reject access from untrusted scripts based on origin value.
|
||||
|
||||
pass # Always accept.
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
while True:
|
||||
line = request.ws_stream.receive_message()
|
||||
if line is None:
|
||||
return
|
||||
if isinstance(line, unicode):
|
||||
request.ws_stream.send_message(line, binary=False)
|
||||
if line == _GOODBYE_MESSAGE:
|
||||
return
|
||||
else:
|
||||
request.ws_stream.send_message(line, binary=True)
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
54
tests/wpt/web-platform-tests/tools/pywebsocket/example/eventsource.cgi
Executable file
54
tests/wpt/web-platform-tests/tools/pywebsocket/example/eventsource.cgi
Executable file
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2013, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
"""This CGI script generates text/event-stream type data stream for testing
|
||||
the Server-Sent Events.
|
||||
|
||||
It will only work correctly with HTTP servers that do not buffer the output of
|
||||
CGI scripts.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.stdout.write('Content-type: text/event-stream\r\n\r\n')
|
||||
|
||||
id = 0
|
||||
|
||||
while True:
|
||||
sys.stdout.write('data: Hello\r\nid: %d\r\n\r\n' % id)
|
||||
sys.stdout.flush()
|
||||
|
||||
id = id + 1
|
||||
|
||||
time.sleep(1)
|
|
@ -0,0 +1,74 @@
|
|||
<!--
|
||||
Copyright 2013, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Simple example of the Server-Sent Events
|
||||
http://dev.w3.org/html5/eventsource/
|
||||
|
||||
For comparison with the WebSocket Protocol & API.
|
||||
|
||||
Run the pywebsocket with the --cgi_path parameter.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Server-Sent Events Example</title>
|
||||
<script>
|
||||
var eventSource = null;
|
||||
|
||||
function addToLog(data) {
|
||||
logBox.value += data + '\n';
|
||||
logBox.scrollTop = 1000000;
|
||||
}
|
||||
|
||||
function init() {
|
||||
logBox = document.getElementById('log');
|
||||
|
||||
eventSource = new EventSource('/eventsource.cgi');
|
||||
eventSource.onopen = function() {
|
||||
addToLog('onopen (readyState = ' + eventSource.readyState + ')');
|
||||
}
|
||||
eventSource.onmessage = function(event) {
|
||||
addToLog(event.data);
|
||||
}
|
||||
eventSource.onerror = function(event) {
|
||||
addToLog('onerror (readyState = ' + eventSource.readyState + ')');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<textarea id="log" rows="10" cols="40" readonly></textarea>
|
||||
<p style="font-size: small">
|
||||
Make sure that pywebsocket is run with --cgi_path parameter.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,163 @@
|
|||
<!--
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the COPYING file or at
|
||||
https://developers.google.com/open-source/licenses/bsd
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Fetch API benchmark</title>
|
||||
<script src="util_main.js"></script>
|
||||
<script src="util.js"></script>
|
||||
<script src="fetch_benchmark.js"></script>
|
||||
<script>
|
||||
var addressBox = null;
|
||||
|
||||
function getConfig() {
|
||||
return {
|
||||
prefixUrl: addressBox.value,
|
||||
printSize: getBoolFromCheckBox('printsize'),
|
||||
numFetches: getIntFromInput('numFetches'),
|
||||
// Initial size of messages.
|
||||
numIterations: getIntFromInput('numiterations'),
|
||||
numWarmUpIterations: getIntFromInput('numwarmupiterations'),
|
||||
startSize: getIntFromInput('startsize'),
|
||||
// Stops benchmark when the size of message exceeds this threshold.
|
||||
stopThreshold: getIntFromInput('stopthreshold'),
|
||||
multipliers: getFloatArrayFromInput('multipliers'),
|
||||
verifyData: getBoolFromCheckBox('verifydata'),
|
||||
addToLog: addToLog,
|
||||
addToSummary: addToSummary,
|
||||
measureValue: measureValue,
|
||||
notifyAbort: notifyAbort
|
||||
};
|
||||
}
|
||||
|
||||
function onSendBenchmark() {
|
||||
var config = getConfig();
|
||||
config.dataType = getStringFromRadioBox('datatyperadio');
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'sendBenchmark');
|
||||
}
|
||||
|
||||
function onReceiveBenchmark() {
|
||||
var config = getConfig();
|
||||
config.dataType = getStringFromRadioBox('datatyperadio');
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'receiveBenchmark');
|
||||
}
|
||||
|
||||
function onBatchBenchmark() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'batchBenchmark');
|
||||
}
|
||||
|
||||
function onStop() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'stop');
|
||||
}
|
||||
|
||||
function init() {
|
||||
addressBox = document.getElementById('address');
|
||||
logBox = document.getElementById('log');
|
||||
|
||||
summaryBox = document.getElementById('summary');
|
||||
|
||||
// Special address of pywebsocket for XHR/Fetch API benchmark.
|
||||
addressBox.value = '/073be001e10950692ccbf3a2ad21c245';
|
||||
|
||||
addToLog(window.navigator.userAgent.toLowerCase());
|
||||
addToSummary(window.navigator.userAgent.toLowerCase());
|
||||
|
||||
initWorker('fetch', '');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
|
||||
<form id="benchmark_form">
|
||||
url prefix <input type="text" id="address" size="40">
|
||||
<input type="button" value="send" onclick="onSendBenchmark()">
|
||||
<input type="button" value="receive" onclick="onReceiveBenchmark()">
|
||||
<input type="button" value="batch" onclick="onBatchBenchmark()">
|
||||
<input type="button" value="stop" onclick="onStop()">
|
||||
|
||||
<br/>
|
||||
|
||||
<input type="checkbox" id="printsize" checked>
|
||||
<label for="printsize">Print size and time per message</label>
|
||||
<input type="checkbox" id="verifydata" checked>
|
||||
<label for="verifydata">Verify data</label>
|
||||
<input type="checkbox" id="worker">
|
||||
<label for="worker">Run on worker</label>
|
||||
|
||||
<br/>
|
||||
|
||||
Parameters:
|
||||
|
||||
<br/>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Number of fetch() requests</td>
|
||||
<td><input type="text" id="numFetches" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of iterations</td>
|
||||
<td><input type="text" id="numiterations" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of warm-up iterations</td>
|
||||
<td><input type="text" id="numwarmupiterations" value="0"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start size</td>
|
||||
<td><input type="text" id="startsize" value="10240"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stop threshold</td>
|
||||
<td><input type="text" id="stopthreshold" value="102400000"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multipliers</td>
|
||||
<td><input type="text" id="multipliers" value="5, 2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Set data type
|
||||
<input type="radio"
|
||||
name="datatyperadio"
|
||||
id="datatyperadiotext"
|
||||
value="text"
|
||||
checked><label for="datatyperadiotext">text</label>
|
||||
<input type="radio"
|
||||
name="datatyperadio"
|
||||
id="datatyperadioblob"
|
||||
value="blob"
|
||||
><label for="datatyperadioblob">blob</label>
|
||||
<input type="radio"
|
||||
name="datatyperadio"
|
||||
id="datatyperadioarraybuffer"
|
||||
value="arraybuffer"
|
||||
><label for="datatyperadioarraybuffer">arraybuffer</label>
|
||||
</form>
|
||||
|
||||
<div id="log_div">
|
||||
<textarea
|
||||
id="log" rows="20" style="width: 100%" readonly></textarea>
|
||||
</div>
|
||||
<div id="summary_div">
|
||||
Summary
|
||||
<textarea
|
||||
id="summary" rows="20" style="width: 100%" readonly></textarea>
|
||||
</div>
|
||||
|
||||
<div id="note_div">
|
||||
Note:
|
||||
<ul>
|
||||
<li>Effect of RTT and time spent for ArrayBuffer creation in receive benchmarks are not eliminated.</li>
|
||||
<li>The Stddev column shows NaN when the number of iterations is set to 1.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,225 @@
|
|||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the COPYING file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
var isWorker = typeof importScripts !== "undefined";
|
||||
|
||||
if (isWorker) {
|
||||
// Running on a worker
|
||||
importScripts('util.js', 'util_worker.js');
|
||||
}
|
||||
|
||||
// Namespace for holding globals.
|
||||
var benchmark = {};
|
||||
benchmark.startTimeInMs = 0;
|
||||
|
||||
var timerID = null;
|
||||
|
||||
function sendBenchmarkStep(size, config, isWarmUp) {
|
||||
timerID = null;
|
||||
benchmark.startTimeInMs = null;
|
||||
|
||||
// Prepare data.
|
||||
var dataArray = [];
|
||||
for (var i = 0; i < config.numFetches; ++i) {
|
||||
var data = null;
|
||||
if (config.dataType == 'arraybuffer' ||
|
||||
config.dataType == 'blob') {
|
||||
data = new ArrayBuffer(size);
|
||||
|
||||
fillArrayBuffer(data, 0x61);
|
||||
|
||||
if (config.dataType == 'blob') {
|
||||
data = new Blob([data]);
|
||||
}
|
||||
} else {
|
||||
data = repeatString('a', size);
|
||||
}
|
||||
|
||||
dataArray.push(data);
|
||||
}
|
||||
|
||||
// Start time measuring.
|
||||
benchmark.startTimeInMs = getTimeStamp();
|
||||
|
||||
// Start fetch.
|
||||
var promises = [];
|
||||
for (var i = 0; i < config.numFetches; ++i) {
|
||||
var data = dataArray[i];
|
||||
var promise = fetch(config.prefixUrl + '_send',
|
||||
{method: 'POST', body: data})
|
||||
.then(function (response) {
|
||||
if (response.status != 200) {
|
||||
config.addToLog('Failed (status=' + response.status + ')');
|
||||
return Promise.reject();
|
||||
}
|
||||
// Check and warn if proxy is enabled.
|
||||
if (response.headers.get('Via') !== null) {
|
||||
config.addToLog('WARNING: proxy seems enabled.');
|
||||
}
|
||||
if (config.verifyData) {
|
||||
return response.text()
|
||||
.then(function(text) {
|
||||
if (!verifyAcknowledgement(config, text, size)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
promises.push(promise);
|
||||
}
|
||||
|
||||
// Finish and report time measuring.
|
||||
Promise.all(promises)
|
||||
.then(function() {
|
||||
if (benchmark.startTimeInMs == null) {
|
||||
config.addToLog('startTimeInMs not set');
|
||||
return Promise.reject();
|
||||
}
|
||||
calculateAndLogResult(config, size, benchmark.startTimeInMs,
|
||||
size * config.numFetches, isWarmUp);
|
||||
runNextTask(config);
|
||||
})
|
||||
.catch(function(e) {
|
||||
config.addToLog("ERROR: " + e);
|
||||
config.notifyAbort();
|
||||
});
|
||||
}
|
||||
|
||||
function receiveBenchmarkStep(size, config, isWarmUp) {
|
||||
timerID = null;
|
||||
benchmark.startTimeInMs = null;
|
||||
|
||||
// Start time measuring.
|
||||
benchmark.startTimeInMs = getTimeStamp();
|
||||
|
||||
// Start fetch.
|
||||
var promises = [];
|
||||
for (var i = 0; i < config.numFetches; ++i) {
|
||||
var request;
|
||||
if (config.methodAndCache === 'GET-NOCACHE') {
|
||||
request = new Request(config.prefixUrl + '_receive_getnocache?' + size,
|
||||
{method: 'GET'});
|
||||
} else if (config.methodAndCache === 'GET-CACHE') {
|
||||
request = new Request(config.prefixUrl + '_receive_getcache?' + size,
|
||||
{method: 'GET'});
|
||||
} else {
|
||||
request = new Request(config.prefixUrl + '_receive',
|
||||
{method: 'POST', body: size + ' none'});
|
||||
}
|
||||
var promise = fetch(request)
|
||||
.then(function(response) {
|
||||
if (response.status != 200) {
|
||||
config.addToLog('Failed (status=' + this.status + ')');
|
||||
return Promise.reject();
|
||||
}
|
||||
// Check and warn if proxy is enabled.
|
||||
if (response.headers.get('Via') !== null) {
|
||||
config.addToLog('WARNING: proxy seems enabled.');
|
||||
}
|
||||
if (config.dataType === 'arraybuffer') {
|
||||
return response.arrayBuffer()
|
||||
.then(function(arrayBuffer) {
|
||||
return [arrayBuffer.byteLength,
|
||||
(!config.verifyData ||
|
||||
verifyArrayBuffer(arrayBuffer, 0x61))];
|
||||
});
|
||||
} else if (config.dataType == 'blob') {
|
||||
return response.blob()
|
||||
.then(function(blob) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (config.verifyData) {
|
||||
verifyBlob(config, blob, 0x61,
|
||||
function(receivedSize, verificationResult) {
|
||||
resolve([receivedSize, verificationResult]);
|
||||
});
|
||||
} else {
|
||||
resolve([blob.size, true]);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return response.text()
|
||||
.then(function(text) {
|
||||
return [text.length,
|
||||
(!config.verifyData ||
|
||||
text == repeatString('a', text.length))];
|
||||
});
|
||||
}
|
||||
})
|
||||
.then(function(receivedSizeAndVerificationResult) {
|
||||
var receivedSize = receivedSizeAndVerificationResult[0];
|
||||
var verificationResult = receivedSizeAndVerificationResult[1];
|
||||
if (receivedSize !== size) {
|
||||
config.addToLog('Expected ' + size +
|
||||
'B but received ' + receivedSize + 'B');
|
||||
return Promise.reject();
|
||||
}
|
||||
if (!verificationResult) {
|
||||
config.addToLog('Response verification failed');
|
||||
return Promise.reject();
|
||||
}
|
||||
});
|
||||
promises.push(promise);
|
||||
}
|
||||
|
||||
// Finish and report time measuring.
|
||||
Promise.all(promises)
|
||||
.then(function() {
|
||||
if (benchmark.startTimeInMs == null) {
|
||||
config.addToLog('startTimeInMs not set');
|
||||
return Promise.reject();
|
||||
}
|
||||
calculateAndLogResult(config, size, benchmark.startTimeInMs,
|
||||
size * config.numFetches, isWarmUp);
|
||||
runNextTask(config);
|
||||
})
|
||||
.catch(function(e) {
|
||||
config.addToLog("ERROR: " + e);
|
||||
config.notifyAbort();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function getConfigString(config) {
|
||||
return '(' + config.dataType +
|
||||
', verifyData=' + config.verifyData +
|
||||
', ' + (isWorker ? 'Worker' : 'Main') +
|
||||
', numFetches=' + config.numFetches +
|
||||
', numIterations=' + config.numIterations +
|
||||
', numWarmUpIterations=' + config.numWarmUpIterations +
|
||||
')';
|
||||
}
|
||||
|
||||
function startBenchmark(config) {
|
||||
clearTimeout(timerID);
|
||||
|
||||
runNextTask(config);
|
||||
}
|
||||
|
||||
function batchBenchmark(originalConfig) {
|
||||
originalConfig.addToLog('Batch benchmark');
|
||||
|
||||
tasks = [];
|
||||
clearAverageData();
|
||||
|
||||
var dataTypes = ['text', 'blob', 'arraybuffer'];
|
||||
var stepFuncs = [sendBenchmarkStep, receiveBenchmarkStep];
|
||||
var names = ['Send', 'Receive'];
|
||||
for (var i = 0; i < stepFuncs.length; ++i) {
|
||||
for (var j = 0; j < dataTypes.length; ++j) {
|
||||
var config = cloneConfig(originalConfig);
|
||||
config.dataType = dataTypes[j];
|
||||
addTasks(config, stepFuncs[i]);
|
||||
addResultReportingTask(config,
|
||||
names[i] + ' benchmark ' + getConfigString(config));
|
||||
}
|
||||
}
|
||||
|
||||
startBenchmark(config);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<script src="util.js"></script>
|
||||
<script src="performance_test_iframe.js"></script>
|
||||
<script src="fetch_benchmark.js"></script>
|
||||
</head>
|
|
@ -0,0 +1,11 @@
|
|||
# websocket handler map file, used by standalone.py -m option.
|
||||
# A line starting with '#' is a comment line.
|
||||
# Each line consists of 'alias_resource_path' and 'existing_resource_path'
|
||||
# separated by spaces.
|
||||
# Aliasing is processed from the top to the bottom of the line, and
|
||||
# 'existing_resource_path' must exist before it is aliased.
|
||||
# For example,
|
||||
# / /echo
|
||||
# means that a request to '/' will be handled by handlers for '/echo'.
|
||||
/ /echo
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright 2013, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
request.extra_headers.append(
|
||||
('Strict-Transport-Security', 'max-age=86400'))
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
request.ws_stream.send_message('Hello', binary=False)
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2012, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
from mod_pywebsocket import msgutil
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
pass
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
raise msgutil.BadOperationException('Intentional')
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,44 @@
|
|||
# Copyright 2011, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# This example is derived from test/testdata/handlers/origin_check_wsh.py.
|
||||
|
||||
|
||||
def web_socket_do_extra_handshake(request):
|
||||
if request.ws_origin == 'http://example.com':
|
||||
return
|
||||
raise ValueError('Unacceptable origin: %r' % request.ws_origin)
|
||||
|
||||
|
||||
def web_socket_transfer_data(request):
|
||||
request.connection.write('origin_check_wsh.py is called for %s, %s' %
|
||||
(request.ws_resource, request.ws_protocol))
|
||||
|
||||
|
||||
# vi:sts=4 sw=4 et
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<script src="util.js"></script>
|
||||
<script src="performance_test_iframe.js"></script>
|
||||
<script src="benchmark.js"></script>
|
||||
</head>
|
|
@ -0,0 +1,66 @@
|
|||
function perfTestAddToLog(text) {
|
||||
parent.postMessage({'command': 'log', 'value': text}, '*');
|
||||
}
|
||||
|
||||
function perfTestAddToSummary(text) {
|
||||
}
|
||||
|
||||
function perfTestMeasureValue(value) {
|
||||
parent.postMessage({'command': 'measureValue', 'value': value}, '*');
|
||||
}
|
||||
|
||||
function perfTestNotifyAbort() {
|
||||
parent.postMessage({'command': 'notifyAbort'}, '*');
|
||||
}
|
||||
|
||||
function getConfigForPerformanceTest(connectionType, dataType, async,
|
||||
verifyData, numIterations,
|
||||
numWarmUpIterations) {
|
||||
var prefixUrl;
|
||||
if (connectionType === 'WebSocket') {
|
||||
prefixUrl = 'ws://' + location.host + '/benchmark_helper';
|
||||
} else {
|
||||
// XHR or fetch
|
||||
prefixUrl = 'http://' + location.host + '/073be001e10950692ccbf3a2ad21c245';
|
||||
}
|
||||
|
||||
return {
|
||||
prefixUrl: prefixUrl,
|
||||
printSize: true,
|
||||
numXHRs: 1,
|
||||
numFetches: 1,
|
||||
numSockets: 1,
|
||||
// + 1 is for a warmup iteration by the Telemetry framework.
|
||||
numIterations: numIterations + numWarmUpIterations + 1,
|
||||
numWarmUpIterations: numWarmUpIterations,
|
||||
minTotal: 10240000,
|
||||
startSize: 10240000,
|
||||
stopThreshold: 10240000,
|
||||
multipliers: [2],
|
||||
verifyData: verifyData,
|
||||
dataType: dataType,
|
||||
async: async,
|
||||
addToLog: perfTestAddToLog,
|
||||
addToSummary: perfTestAddToSummary,
|
||||
measureValue: perfTestMeasureValue,
|
||||
notifyAbort: perfTestNotifyAbort
|
||||
};
|
||||
}
|
||||
|
||||
var data;
|
||||
onmessage = function(message) {
|
||||
var action;
|
||||
if (message.data.command === 'start') {
|
||||
data = message.data;
|
||||
initWorker(data.connectionType, 'http://' + location.host);
|
||||
action = data.benchmarkName;
|
||||
} else {
|
||||
action = 'stop';
|
||||
}
|
||||
|
||||
var config = getConfigForPerformanceTest(data.connectionType, data.dataType,
|
||||
data.async, data.verifyData,
|
||||
data.numIterations,
|
||||
data.numWarmUpIterations);
|
||||
doAction(config, data.isWorker, action);
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2011, Google Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#
|
||||
# Sample configuration file for apache2
|
||||
#
|
||||
LogLevel debug
|
||||
<IfModule python_module>
|
||||
PythonPath "sys.path+['/mod_pywebsocket']"
|
||||
PythonOption mod_pywebsocket.handler_root /var/www
|
||||
PythonOption mod_pywebsocket.handler_scan /var/www/ws
|
||||
#PythonOption mod_pywebsocket.allow_draft75 On
|
||||
<Location /ws>
|
||||
PythonHeaderParserHandler mod_pywebsocket.headerparserhandler
|
||||
</Location>
|
||||
</IfModule>
|
28
tests/wpt/web-platform-tests/tools/pywebsocket/example/special_headers.cgi
Executable file
28
tests/wpt/web-platform-tests/tools/pywebsocket/example/special_headers.cgi
Executable file
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2014 Google Inc. All rights reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the COPYING file or at
|
||||
# https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
"""CGI script sample for testing effect of HTTP headers on the origin page.
|
||||
|
||||
Note that CGI scripts don't work on the standalone pywebsocket running in TLS
|
||||
mode.
|
||||
"""
|
||||
|
||||
|
||||
print """Content-type: text/html
|
||||
Content-Security-Policy: connect-src self
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
var socket = new WebSocket("ws://example.com");
|
||||
</script>
|
||||
</body>
|
||||
</html>"""
|
327
tests/wpt/web-platform-tests/tools/pywebsocket/example/util.js
Normal file
327
tests/wpt/web-platform-tests/tools/pywebsocket/example/util.js
Normal file
|
@ -0,0 +1,327 @@
|
|||
// Copyright 2013, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
// Utilities for example applications (for both main and worker thread).
|
||||
|
||||
var results = {};
|
||||
|
||||
function getTimeStamp() {
|
||||
return Date.now();
|
||||
}
|
||||
|
||||
function formatResultInKiB(size, timePerMessageInMs, stddevTimePerMessageInMs,
|
||||
speed, printSize) {
|
||||
if (printSize) {
|
||||
return (size / 1024) +
|
||||
'\t' + timePerMessageInMs.toFixed(3) +
|
||||
(stddevTimePerMessageInMs == -1 ?
|
||||
'' :
|
||||
'\t' + stddevTimePerMessageInMs.toFixed(3)) +
|
||||
'\t' + speed.toFixed(3);
|
||||
} else {
|
||||
return speed.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function clearAverageData() {
|
||||
results = {};
|
||||
}
|
||||
|
||||
function reportAverageData(config) {
|
||||
config.addToSummary(
|
||||
'Size[KiB]\tAverage time[ms]\tStddev time[ms]\tSpeed[KB/s]');
|
||||
for (var size in results) {
|
||||
var averageTimePerMessageInMs = results[size].sum_t / results[size].n;
|
||||
var speed = calculateSpeedInKB(size, averageTimePerMessageInMs);
|
||||
// Calculate sample standard deviation
|
||||
var stddevTimePerMessageInMs = Math.sqrt(
|
||||
(results[size].sum_t2 / results[size].n -
|
||||
averageTimePerMessageInMs * averageTimePerMessageInMs) *
|
||||
results[size].n /
|
||||
(results[size].n - 1));
|
||||
config.addToSummary(formatResultInKiB(
|
||||
size, averageTimePerMessageInMs, stddevTimePerMessageInMs, speed,
|
||||
true));
|
||||
}
|
||||
}
|
||||
|
||||
function calculateSpeedInKB(size, timeSpentInMs) {
|
||||
return Math.round(size / timeSpentInMs * 1000) / 1000;
|
||||
}
|
||||
|
||||
function calculateAndLogResult(config, size, startTimeInMs, totalSize,
|
||||
isWarmUp) {
|
||||
var timeSpentInMs = getTimeStamp() - startTimeInMs;
|
||||
var speed = calculateSpeedInKB(totalSize, timeSpentInMs);
|
||||
var timePerMessageInMs = timeSpentInMs / (totalSize / size);
|
||||
if (!isWarmUp) {
|
||||
config.measureValue(timePerMessageInMs);
|
||||
if (!results[size]) {
|
||||
results[size] = {n: 0, sum_t: 0, sum_t2: 0};
|
||||
}
|
||||
results[size].n ++;
|
||||
results[size].sum_t += timePerMessageInMs;
|
||||
results[size].sum_t2 += timePerMessageInMs * timePerMessageInMs;
|
||||
}
|
||||
config.addToLog(formatResultInKiB(size, timePerMessageInMs, -1, speed,
|
||||
config.printSize));
|
||||
}
|
||||
|
||||
function repeatString(str, count) {
|
||||
var data = '';
|
||||
var expChunk = str;
|
||||
var remain = count;
|
||||
while (true) {
|
||||
if (remain % 2) {
|
||||
data += expChunk;
|
||||
remain = (remain - 1) / 2;
|
||||
} else {
|
||||
remain /= 2;
|
||||
}
|
||||
|
||||
if (remain == 0)
|
||||
break;
|
||||
|
||||
expChunk = expChunk + expChunk;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function fillArrayBuffer(buffer, c) {
|
||||
var i;
|
||||
|
||||
var u32Content = c * 0x01010101;
|
||||
|
||||
var u32Blocks = Math.floor(buffer.byteLength / 4);
|
||||
var u32View = new Uint32Array(buffer, 0, u32Blocks);
|
||||
// length attribute is slow on Chrome. Don't use it for loop condition.
|
||||
for (i = 0; i < u32Blocks; ++i) {
|
||||
u32View[i] = u32Content;
|
||||
}
|
||||
|
||||
// Fraction
|
||||
var u8Blocks = buffer.byteLength - u32Blocks * 4;
|
||||
var u8View = new Uint8Array(buffer, u32Blocks * 4, u8Blocks);
|
||||
for (i = 0; i < u8Blocks; ++i) {
|
||||
u8View[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
function verifyArrayBuffer(buffer, expectedChar) {
|
||||
var i;
|
||||
|
||||
var expectedU32Value = expectedChar * 0x01010101;
|
||||
|
||||
var u32Blocks = Math.floor(buffer.byteLength / 4);
|
||||
var u32View = new Uint32Array(buffer, 0, u32Blocks);
|
||||
for (i = 0; i < u32Blocks; ++i) {
|
||||
if (u32View[i] != expectedU32Value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var u8Blocks = buffer.byteLength - u32Blocks * 4;
|
||||
var u8View = new Uint8Array(buffer, u32Blocks * 4, u8Blocks);
|
||||
for (i = 0; i < u8Blocks; ++i) {
|
||||
if (u8View[i] != expectedChar) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function verifyBlob(config, blob, expectedChar, doneCallback) {
|
||||
var reader = new FileReader(blob);
|
||||
reader.onerror = function() {
|
||||
config.addToLog('FileReader Error: ' + reader.error.message);
|
||||
doneCallback(blob.size, false);
|
||||
}
|
||||
reader.onloadend = function() {
|
||||
var result = verifyArrayBuffer(reader.result, expectedChar);
|
||||
doneCallback(blob.size, result);
|
||||
}
|
||||
reader.readAsArrayBuffer(blob);
|
||||
}
|
||||
|
||||
function verifyAcknowledgement(config, message, size) {
|
||||
if (typeof message != 'string') {
|
||||
config.addToLog('Invalid ack type: ' + typeof message);
|
||||
return false;
|
||||
}
|
||||
var parsedAck = parseInt(message);
|
||||
if (isNaN(parsedAck)) {
|
||||
config.addToLog('Invalid ack value: ' + message);
|
||||
return false;
|
||||
}
|
||||
if (parsedAck != size) {
|
||||
config.addToLog(
|
||||
'Expected ack for ' + size + 'B but received one for ' + parsedAck +
|
||||
'B');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function cloneConfig(obj) {
|
||||
var newObj = {};
|
||||
for (key in obj) {
|
||||
newObj[key] = obj[key];
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
|
||||
var tasks = [];
|
||||
|
||||
function runNextTask(config) {
|
||||
var task = tasks.shift();
|
||||
if (task == undefined) {
|
||||
config.addToLog('Finished');
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
timerID = setTimeout(task, 0);
|
||||
}
|
||||
|
||||
function buildLegendString(config) {
|
||||
var legend = ''
|
||||
if (config.printSize)
|
||||
legend = 'Message size in KiB, Time/message in ms, ';
|
||||
legend += 'Speed in kB/s';
|
||||
return legend;
|
||||
}
|
||||
|
||||
function addTasks(config, stepFunc) {
|
||||
for (var i = 0;
|
||||
i < config.numWarmUpIterations + config.numIterations; ++i) {
|
||||
var multiplierIndex = 0;
|
||||
for (var size = config.startSize;
|
||||
size <= config.stopThreshold;
|
||||
++multiplierIndex) {
|
||||
var task = stepFunc.bind(
|
||||
null,
|
||||
size,
|
||||
config,
|
||||
i < config.numWarmUpIterations);
|
||||
tasks.push(task);
|
||||
var multiplier = config.multipliers[
|
||||
multiplierIndex % config.multipliers.length];
|
||||
if (multiplier <= 1) {
|
||||
config.addToLog('Invalid multiplier ' + multiplier);
|
||||
config.notifyAbort();
|
||||
throw new Error('Invalid multipler');
|
||||
}
|
||||
size = Math.ceil(size * multiplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addResultReportingTask(config, title) {
|
||||
tasks.push(function(){
|
||||
timerID = null;
|
||||
config.addToSummary(title);
|
||||
reportAverageData(config);
|
||||
clearAverageData();
|
||||
runNextTask(config);
|
||||
});
|
||||
}
|
||||
|
||||
function sendBenchmark(config) {
|
||||
config.addToLog('Send benchmark');
|
||||
config.addToLog(buildLegendString(config));
|
||||
|
||||
tasks = [];
|
||||
clearAverageData();
|
||||
addTasks(config, sendBenchmarkStep);
|
||||
addResultReportingTask(config, 'Send Benchmark ' + getConfigString(config));
|
||||
startBenchmark(config);
|
||||
}
|
||||
|
||||
function receiveBenchmark(config) {
|
||||
config.addToLog('Receive benchmark');
|
||||
config.addToLog(buildLegendString(config));
|
||||
|
||||
tasks = [];
|
||||
clearAverageData();
|
||||
addTasks(config, receiveBenchmarkStep);
|
||||
addResultReportingTask(config,
|
||||
'Receive Benchmark ' + getConfigString(config));
|
||||
startBenchmark(config);
|
||||
}
|
||||
|
||||
function stop(config) {
|
||||
clearTimeout(timerID);
|
||||
timerID = null;
|
||||
tasks = [];
|
||||
config.addToLog('Stopped');
|
||||
cleanup();
|
||||
}
|
||||
|
||||
var worker;
|
||||
|
||||
function initWorker(connectionType, origin) {
|
||||
var scriptPath =
|
||||
connectionType === 'WebSocket' ? '/benchmark.js' :
|
||||
connectionType === 'XHR' ? '/xhr_benchmark.js' :
|
||||
'/fetch_benchmark.js'; // connectionType === 'fetch'
|
||||
worker = new Worker(origin + scriptPath);
|
||||
}
|
||||
|
||||
function doAction(config, isWindowToWorker, action) {
|
||||
if (isWindowToWorker) {
|
||||
worker.onmessage = function(addToLog, addToSummary,
|
||||
measureValue, notifyAbort, message) {
|
||||
if (message.data.type === 'addToLog')
|
||||
addToLog(message.data.data);
|
||||
else if (message.data.type === 'addToSummary')
|
||||
addToSummary(message.data.data);
|
||||
else if (message.data.type === 'measureValue')
|
||||
measureValue(message.data.data);
|
||||
else if (message.data.type === 'notifyAbort')
|
||||
notifyAbort();
|
||||
}.bind(undefined, config.addToLog, config.addToSummary,
|
||||
config.measureValue, config.notifyAbort);
|
||||
config.addToLog = undefined;
|
||||
config.addToSummary = undefined;
|
||||
config.measureValue = undefined;
|
||||
config.notifyAbort = undefined;
|
||||
worker.postMessage({type: action, config: config});
|
||||
} else {
|
||||
if (action === 'sendBenchmark')
|
||||
sendBenchmark(config);
|
||||
else if (action === 'receiveBenchmark')
|
||||
receiveBenchmark(config);
|
||||
else if (action === 'batchBenchmark')
|
||||
batchBenchmark(config);
|
||||
else if (action === 'stop')
|
||||
stop(config);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the COPYING file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
// Utilities for example applications (for the main thread only).
|
||||
|
||||
var logBox = null;
|
||||
var queuedLog = '';
|
||||
|
||||
var summaryBox = null;
|
||||
|
||||
function queueLog(log) {
|
||||
queuedLog += log + '\n';
|
||||
}
|
||||
|
||||
function addToLog(log) {
|
||||
logBox.value += queuedLog;
|
||||
queuedLog = '';
|
||||
logBox.value += log + '\n';
|
||||
logBox.scrollTop = 1000000;
|
||||
}
|
||||
|
||||
function addToSummary(log) {
|
||||
summaryBox.value += log + '\n';
|
||||
summaryBox.scrollTop = 1000000;
|
||||
}
|
||||
|
||||
// value: execution time in milliseconds.
|
||||
// config.measureValue is intended to be used in Performance Tests.
|
||||
// Do nothing here in non-PerformanceTest.
|
||||
function measureValue(value) {
|
||||
}
|
||||
|
||||
// config.notifyAbort is called when the benchmark failed and aborted, and
|
||||
// intended to be used in Performance Tests.
|
||||
// Do nothing here in non-PerformanceTest.
|
||||
function notifyAbort() {
|
||||
}
|
||||
|
||||
function getIntFromInput(id) {
|
||||
return parseInt(document.getElementById(id).value);
|
||||
}
|
||||
|
||||
function getStringFromRadioBox(name) {
|
||||
var list = document.getElementById('benchmark_form')[name];
|
||||
for (var i = 0; i < list.length; ++i)
|
||||
if (list.item(i).checked)
|
||||
return list.item(i).value;
|
||||
return undefined;
|
||||
}
|
||||
function getBoolFromCheckBox(id) {
|
||||
return document.getElementById(id).checked;
|
||||
}
|
||||
|
||||
function getIntArrayFromInput(id) {
|
||||
var strArray = document.getElementById(id).value.split(',');
|
||||
return strArray.map(function(str) { return parseInt(str, 10); });
|
||||
}
|
||||
|
||||
function getFloatArrayFromInput(id) {
|
||||
var strArray = document.getElementById(id).value.split(',');
|
||||
return strArray.map(parseFloat);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the COPYING file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
// Utilities for example applications (for the worker threads only).
|
||||
|
||||
onmessage = function (message) {
|
||||
var config = message.data.config;
|
||||
config.addToLog = function(text) {
|
||||
postMessage({type: 'addToLog', data: text}); };
|
||||
config.addToSummary = function(text) {
|
||||
postMessage({type: 'addToSummary', data: text}); };
|
||||
config.measureValue = function(value) {
|
||||
postMessage({type: 'measureValue', data: value}); };
|
||||
config.notifyAbort = function() { postMessage({type: 'notifyAbort'}); };
|
||||
|
||||
doAction(config, false, message.data.type);
|
||||
};
|
|
@ -0,0 +1,212 @@
|
|||
<!--
|
||||
Copyright 2013, Google Inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>XMLHttpRequest benchmark</title>
|
||||
<script src="util_main.js"></script>
|
||||
<script src="util.js"></script>
|
||||
<script src="xhr_benchmark.js"></script>
|
||||
<script>
|
||||
var addressBox = null;
|
||||
|
||||
function getConfig() {
|
||||
return {
|
||||
prefixUrl: addressBox.value,
|
||||
printSize: getBoolFromCheckBox('printsize'),
|
||||
numXHRs: getIntFromInput('numXHRs'),
|
||||
async: getBoolFromCheckBox('async'),
|
||||
// Initial size of messages.
|
||||
numIterations: getIntFromInput('numiterations'),
|
||||
numWarmUpIterations: getIntFromInput('numwarmupiterations'),
|
||||
startSize: getIntFromInput('startsize'),
|
||||
// Stops benchmark when the size of message exceeds this threshold.
|
||||
stopThreshold: getIntFromInput('stopthreshold'),
|
||||
multipliers: getFloatArrayFromInput('multipliers'),
|
||||
verifyData: getBoolFromCheckBox('verifydata'),
|
||||
methodAndCache: getStringFromRadioBox('methodandcache'),
|
||||
addToLog: addToLog,
|
||||
addToSummary: addToSummary,
|
||||
measureValue: measureValue,
|
||||
notifyAbort: notifyAbort
|
||||
};
|
||||
}
|
||||
|
||||
function onSendBenchmark() {
|
||||
var config = getConfig();
|
||||
config.dataType = getStringFromRadioBox('datatyperadio');
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'sendBenchmark');
|
||||
}
|
||||
|
||||
function onReceiveBenchmark() {
|
||||
var config = getConfig();
|
||||
config.dataType = getStringFromRadioBox('datatyperadio');
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'receiveBenchmark');
|
||||
}
|
||||
|
||||
function onBatchBenchmark() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'batchBenchmark');
|
||||
}
|
||||
|
||||
function onStop() {
|
||||
var config = getConfig();
|
||||
doAction(config, getBoolFromCheckBox('worker'), 'stop');
|
||||
}
|
||||
|
||||
function init() {
|
||||
addressBox = document.getElementById('address');
|
||||
logBox = document.getElementById('log');
|
||||
|
||||
summaryBox = document.getElementById('summary');
|
||||
|
||||
// Special address of pywebsocket for XHR benchmark.
|
||||
addressBox.value = '/073be001e10950692ccbf3a2ad21c245';
|
||||
|
||||
addToLog(window.navigator.userAgent.toLowerCase());
|
||||
addToSummary(window.navigator.userAgent.toLowerCase());
|
||||
|
||||
initWorker('XHR', '');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
|
||||
<form id="benchmark_form">
|
||||
url prefix <input type="text" id="address" size="40">
|
||||
<input type="button" value="send" onclick="onSendBenchmark()">
|
||||
<input type="button" value="receive" onclick="onReceiveBenchmark()">
|
||||
<input type="button" value="batch" onclick="onBatchBenchmark()">
|
||||
<input type="button" value="stop" onclick="onStop()">
|
||||
|
||||
<br/>
|
||||
|
||||
<input type="checkbox" id="printsize" checked>
|
||||
<label for="printsize">Print size and time per message</label>
|
||||
<input type="checkbox" id="verifydata" checked>
|
||||
<label for="verifydata">Verify data</label>
|
||||
<input type="checkbox" id="worker">
|
||||
<label for="worker">Run on worker</label>
|
||||
<input type="checkbox" id="async" checked>
|
||||
<label for="async">Async</label><br>
|
||||
(Receive && Non-Worker && Sync is not supported by spec)
|
||||
|
||||
<br/>
|
||||
|
||||
Parameters:
|
||||
|
||||
<br/>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Num XHRs</td>
|
||||
<td><input type="text" id="numXHRs" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of iterations</td>
|
||||
<td><input type="text" id="numiterations" value="1"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Number of warm-up iterations</td>
|
||||
<td><input type="text" id="numwarmupiterations" value="0"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start size</td>
|
||||
<td><input type="text" id="startsize" value="10240"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stop threshold</td>
|
||||
<td><input type="text" id="stopthreshold" value="102400000"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multipliers</td>
|
||||
<td><input type="text" id="multipliers" value="5, 2"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Set data type
|
||||
<input type="radio"
|
||||
name="datatyperadio"
|
||||
id="datatyperadiotext"
|
||||
value="text"
|
||||
checked><label for="datatyperadiotext">text</label>
|
||||
<input type="radio"
|
||||
name="datatyperadio"
|
||||
id="datatyperadioblob"
|
||||
value="blob"
|
||||
><label for="datatyperadioblob">blob</label>
|
||||
<input type="radio"
|
||||
name="datatyperadio"
|
||||
id="datatyperadioarraybuffer"
|
||||
value="arraybuffer"
|
||||
><label for="datatyperadioarraybuffer">arraybuffer</label>
|
||||
|
||||
<br>
|
||||
Set HTTP method and cache control
|
||||
<input type="radio"
|
||||
name="methodandcache"
|
||||
id="methodandcachePOST"
|
||||
value="POST"
|
||||
checked><label for="methodandcachePOST">POST (No Cache)</label>
|
||||
<input type="radio"
|
||||
name="methodandcache"
|
||||
id="methodandcacheGETNOCACHE"
|
||||
value="GET-NOCACHE"
|
||||
><label for="methodandcacheGETNOCACHE">GET (No Cache)</label>
|
||||
<input type="radio"
|
||||
name="methodandcache"
|
||||
id="methodandcacheGETCACHE"
|
||||
value="GET-CACHE"
|
||||
><label for="methodandcacheGETCACHE">GET (Cache)</label>
|
||||
<br>
|
||||
<span style="font-size: 80%">(Cache control: receive only. Cache is valid for 10 seconds. This config controls Cache-control HTTP response header. Browsers might not cache data e.g. when it is large)</span>
|
||||
</form>
|
||||
|
||||
<div id="log_div">
|
||||
<textarea
|
||||
id="log" rows="20" style="width: 100%" readonly></textarea>
|
||||
</div>
|
||||
<div id="summary_div">
|
||||
Summary
|
||||
<textarea
|
||||
id="summary" rows="20" style="width: 100%" readonly></textarea>
|
||||
</div>
|
||||
|
||||
<div id="note_div">
|
||||
Note:
|
||||
<ul>
|
||||
<li>Effect of RTT and time spent for ArrayBuffer creation in receive benchmarks are not eliminated.</li>
|
||||
<li>The Stddev column shows NaN when the number of iterations is set to 1.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,292 @@
|
|||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the COPYING file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
var isWorker = typeof importScripts !== "undefined";
|
||||
|
||||
if (isWorker) {
|
||||
// Running on a worker
|
||||
importScripts('util.js', 'util_worker.js');
|
||||
}
|
||||
|
||||
// Namespace for holding globals.
|
||||
var benchmark = {};
|
||||
benchmark.startTimeInMs = 0;
|
||||
|
||||
var xhrs = [];
|
||||
|
||||
var timerID = null;
|
||||
|
||||
function destroyAllXHRs() {
|
||||
for (var i = 0; i < xhrs.length; ++i) {
|
||||
xhrs[i].onreadystatechange = null;
|
||||
// Abort XHRs if they are not yet DONE state.
|
||||
// Calling abort() here (i.e. in onreadystatechange handler)
|
||||
// causes "NetworkError" messages in DevTools in sync mode,
|
||||
// even if it is after transition to DONE state.
|
||||
if (xhrs[i].readyState != XMLHttpRequest.DONE)
|
||||
xhrs[i].abort();
|
||||
}
|
||||
xhrs = [];
|
||||
// gc() might be needed for Chrome/Blob
|
||||
}
|
||||
|
||||
function sendBenchmarkStep(size, config, isWarmUp) {
|
||||
timerID = null;
|
||||
|
||||
benchmark.startTimeInMs = null;
|
||||
var totalSize = 0;
|
||||
var totalReplied = 0;
|
||||
|
||||
var onReadyStateChangeHandler = function () {
|
||||
if (this.readyState != this.DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.status != 200) {
|
||||
config.addToLog('Failed (status=' + this.status + ')');
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.verifyData &&
|
||||
!verifyAcknowledgement(config, this.response, size)) {
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
totalReplied += size;
|
||||
|
||||
if (totalReplied < totalSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (benchmark.startTimeInMs == null) {
|
||||
config.addToLog('startTimeInMs not set');
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check and warn if proxy is enabled.
|
||||
if (this.getResponseHeader('Via') !== null) {
|
||||
config.addToLog('WARNING: proxy seems enabled.');
|
||||
}
|
||||
|
||||
calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize,
|
||||
isWarmUp);
|
||||
|
||||
destroyAllXHRs();
|
||||
|
||||
runNextTask(config);
|
||||
};
|
||||
|
||||
for (var i = 0; i < config.numXHRs; ++i) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = onReadyStateChangeHandler;
|
||||
xhrs.push(xhr);
|
||||
}
|
||||
|
||||
var dataArray = [];
|
||||
|
||||
for (var i = 0; i < xhrs.length; ++i) {
|
||||
var data = null;
|
||||
if (config.dataType == 'arraybuffer' ||
|
||||
config.dataType == 'blob') {
|
||||
data = new ArrayBuffer(size);
|
||||
|
||||
fillArrayBuffer(data, 0x61);
|
||||
|
||||
if (config.dataType == 'blob') {
|
||||
data = new Blob([data]);
|
||||
}
|
||||
} else {
|
||||
data = repeatString('a', size);
|
||||
}
|
||||
|
||||
dataArray.push(data);
|
||||
}
|
||||
|
||||
|
||||
benchmark.startTimeInMs = getTimeStamp();
|
||||
totalSize = size * xhrs.length;
|
||||
|
||||
for (var i = 0; i < xhrs.length; ++i) {
|
||||
var data = dataArray[i];
|
||||
var xhr = xhrs[i];
|
||||
xhr.open('POST', config.prefixUrl + '_send', config.async);
|
||||
xhr.send(data);
|
||||
}
|
||||
}
|
||||
|
||||
function receiveBenchmarkStep(size, config, isWarmUp) {
|
||||
timerID = null;
|
||||
|
||||
benchmark.startTimeInMs = null;
|
||||
var totalSize = 0;
|
||||
var totalReplied = 0;
|
||||
|
||||
var checkResultAndContinue = function (bytesReceived, verificationResult) {
|
||||
if (!verificationResult) {
|
||||
config.addToLog('Response verification failed');
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
totalReplied += bytesReceived;
|
||||
|
||||
if (totalReplied < totalSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (benchmark.startTimeInMs == null) {
|
||||
config.addToLog('startTimeInMs not set');
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
calculateAndLogResult(config, size, benchmark.startTimeInMs, totalSize,
|
||||
isWarmUp);
|
||||
|
||||
destroyAllXHRs();
|
||||
|
||||
runNextTask(config);
|
||||
}
|
||||
|
||||
var onReadyStateChangeHandler = function () {
|
||||
if (this.readyState != this.DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.status != 200) {
|
||||
config.addToLog('Failed (status=' + this.status + ')');
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check and warn if proxy is enabled.
|
||||
if (this.getResponseHeader('Via') !== null) {
|
||||
config.addToLog('WARNING: proxy seems enabled.');
|
||||
}
|
||||
|
||||
var bytesReceived = -1;
|
||||
if (this.responseType == 'arraybuffer') {
|
||||
bytesReceived = this.response.byteLength;
|
||||
} else if (this.responseType == 'blob') {
|
||||
bytesReceived = this.response.size;
|
||||
} else {
|
||||
bytesReceived = this.response.length;
|
||||
}
|
||||
if (bytesReceived != size) {
|
||||
config.addToLog('Expected ' + size +
|
||||
'B but received ' + bytesReceived + 'B');
|
||||
destroyAllXHRs();
|
||||
config.notifyAbort();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.responseType == 'arraybuffer') {
|
||||
checkResultAndContinue(bytesReceived,
|
||||
!config.verifyData || verifyArrayBuffer(this.response, 0x61));
|
||||
} else if (this.responseType == 'blob') {
|
||||
if (config.verifyData)
|
||||
verifyBlob(config, this.response, 0x61, checkResultAndContinue);
|
||||
else
|
||||
checkResultAndContinue(bytesReceived, true);
|
||||
} else {
|
||||
checkResultAndContinue(
|
||||
bytesReceived,
|
||||
!config.verifyData ||
|
||||
this.response == repeatString('a', this.response.length));
|
||||
}
|
||||
};
|
||||
|
||||
for (var i = 0; i < config.numXHRs; ++i) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = onReadyStateChangeHandler;
|
||||
xhrs.push(xhr);
|
||||
}
|
||||
|
||||
benchmark.startTimeInMs = getTimeStamp();
|
||||
totalSize = size * xhrs.length;
|
||||
|
||||
for (var i = 0; i < xhrs.length; ++i) {
|
||||
var xhr = xhrs[i];
|
||||
if (config.methodAndCache === 'GET-NOCACHE') {
|
||||
xhr.open('GET', config.prefixUrl + '_receive_getnocache?' + size,
|
||||
config.async);
|
||||
xhr.responseType = config.dataType;
|
||||
xhr.send();
|
||||
} else if (config.methodAndCache === 'GET-CACHE') {
|
||||
xhr.open('GET', config.prefixUrl + '_receive_getcache?' + size,
|
||||
config.async);
|
||||
xhr.responseType = config.dataType;
|
||||
xhr.send();
|
||||
} else {
|
||||
xhr.open('POST', config.prefixUrl + '_receive', config.async);
|
||||
xhr.responseType = config.dataType;
|
||||
xhr.send(size + ' none');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getConfigString(config) {
|
||||
return '(' + config.dataType +
|
||||
', verifyData=' + config.verifyData +
|
||||
', ' + (isWorker ? 'Worker' : 'Main') +
|
||||
', ' + (config.async ? 'Async' : 'Sync') +
|
||||
', numXHRs=' + config.numXHRs +
|
||||
', numIterations=' + config.numIterations +
|
||||
', numWarmUpIterations=' + config.numWarmUpIterations +
|
||||
')';
|
||||
}
|
||||
|
||||
function startBenchmark(config) {
|
||||
clearTimeout(timerID);
|
||||
destroyAllXHRs();
|
||||
|
||||
runNextTask(config);
|
||||
}
|
||||
|
||||
function batchBenchmark(originalConfig) {
|
||||
originalConfig.addToLog('Batch benchmark');
|
||||
|
||||
tasks = [];
|
||||
clearAverageData();
|
||||
|
||||
var dataTypes = ['text', 'blob', 'arraybuffer'];
|
||||
var stepFuncs = [sendBenchmarkStep, receiveBenchmarkStep];
|
||||
var names = ['Send', 'Receive'];
|
||||
var async = [true, false];
|
||||
for (var i = 0; i < stepFuncs.length; ++i) {
|
||||
for (var j = 0; j < dataTypes.length; ++j) {
|
||||
for (var k = 0; k < async.length; ++k) {
|
||||
var config = cloneConfig(originalConfig);
|
||||
config.dataType = dataTypes[j];
|
||||
config.async = async[k];
|
||||
|
||||
// Receive && Non-Worker && Sync is not supported by the spec
|
||||
if (stepFuncs[i] === receiveBenchmarkStep && !isWorker &&
|
||||
!config.async)
|
||||
continue;
|
||||
|
||||
addTasks(config, stepFuncs[i]);
|
||||
addResultReportingTask(config,
|
||||
names[i] + ' benchmark ' + getConfigString(config));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startBenchmark(config);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<!--
|
||||
Copyright 2014 Google Inc. All rights reserved.
|
||||
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the COPYING file or at
|
||||
https://developers.google.com/open-source/licenses/bsd
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>XHR event logger</title>
|
||||
<script src="util_main.js"></script>
|
||||
<script>
|
||||
var events = [];
|
||||
var startTime = 0;
|
||||
|
||||
function run() {
|
||||
events = [];
|
||||
startTime = Date.now();
|
||||
|
||||
function pushToLog(type) {
|
||||
var time = Date.now();
|
||||
if (events.length != 0 && type === events[events.length - 1].type) {
|
||||
events[events.length - 1].count += 1;
|
||||
events[events.length - 1].last = time;
|
||||
} else {
|
||||
events.push({type: type, count: 1, first: time, last: time});
|
||||
}
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
function getProgressEventDump(e) {
|
||||
return '(' + e.lengthComputable + ', ' + e.loaded + ', ' + e.total + ')';
|
||||
}
|
||||
|
||||
var dumpProgressEvent = getBoolFromCheckBox('dumpprogressevent');
|
||||
|
||||
function log(e) {
|
||||
var type = e.type;
|
||||
if (type === 'readystatechange') {
|
||||
type += e.target.readyState;
|
||||
}
|
||||
if (dumpProgressEvent && (e instanceof ProgressEvent)) {
|
||||
type += getProgressEventDump(e);
|
||||
}
|
||||
pushToLog(type);
|
||||
};
|
||||
|
||||
function logUpload(e) {
|
||||
var type = e.type;
|
||||
if (dumpProgressEvent && (e instanceof ProgressEvent)) {
|
||||
type += getProgressEventDump(e);
|
||||
}
|
||||
pushToLog('upload' + type);
|
||||
}
|
||||
|
||||
if (getBoolFromCheckBox('upload')) {
|
||||
var upload = xhr.upload;
|
||||
upload.onloadstart = logUpload;
|
||||
upload.onprogress = logUpload;
|
||||
upload.onabort = logUpload;
|
||||
upload.onerror = logUpload;
|
||||
upload.onload = logUpload;
|
||||
upload.ontimeout = logUpload;
|
||||
upload.onloadend = logUpload;
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = log;
|
||||
xhr.onloadstart = log;
|
||||
xhr.onprogress = log;
|
||||
xhr.onabort = log;
|
||||
xhr.onerror = log;
|
||||
xhr.onload = log;
|
||||
xhr.ontimeout = log;
|
||||
xhr.onloadend = log;
|
||||
|
||||
xhr.open('POST', '/073be001e10950692ccbf3a2ad21c245_receive',
|
||||
getBoolFromCheckBox('async'));
|
||||
var size = getIntFromInput('size');
|
||||
var chunkedMode = 'none';
|
||||
if (getBoolFromCheckBox('chunkedresponse')) {
|
||||
chunkedMode = 'chunked';
|
||||
}
|
||||
xhr.send(size + ' ' + chunkedMode);
|
||||
}
|
||||
|
||||
function print() {
|
||||
var result = '';
|
||||
for (var i = 0; i < events.length; ++i) {
|
||||
var event = events[i];
|
||||
var line = '';
|
||||
line += (event.first - startTime) + "ms";
|
||||
if (event.count > 1)
|
||||
line += "-" + (event.last - startTime) + "ms";
|
||||
else
|
||||
line += " ";
|
||||
while(line.length < 15)
|
||||
line += " ";
|
||||
line += ": " + event.type + ' * ' + event.count + '\n';
|
||||
result += line;
|
||||
}
|
||||
document.getElementById('log').value = result;
|
||||
}
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<textarea id="log" rows="10" cols="70" readonly></textarea>
|
||||
<br/>
|
||||
Size: <input type="text" id="size" value="65536"><br/>
|
||||
<input type="checkbox" id="chunkedresponse">
|
||||
<label for="chunkedresponse">Use Chunked T-E for response</label><br/>
|
||||
<input type="checkbox" id="upload">
|
||||
<label for="upload">Upload progress</label><br/>
|
||||
<input type="checkbox" id="dumpprogressevent">
|
||||
<label for="dumpprogressevent">
|
||||
Dump lengthComputable/loaded/total</label><br/>
|
||||
<input type="checkbox" id="async" checked>
|
||||
<label for="async">Async</label><br/>
|
||||
<input type="button" onclick="run()" value="Run XHR">
|
||||
<input type="button" onclick="print()" value="Print log">
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<script src="util.js"></script>
|
||||
<script src="performance_test_iframe.js"></script>
|
||||
<script src="xhr_benchmark.js"></script>
|
||||
</head>
|
Loading…
Add table
Add a link
Reference in a new issue