netwerk/test/unit/test_spdy.js

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 // test spdy/3
michael@0 2
michael@0 3 var Ci = Components.interfaces;
michael@0 4 var Cc = Components.classes;
michael@0 5
michael@0 6 // Generate a small and a large post with known pre-calculated md5 sums
michael@0 7 function generateContent(size) {
michael@0 8 var content = "";
michael@0 9 for (var i = 0; i < size; i++) {
michael@0 10 content += "0";
michael@0 11 }
michael@0 12 return content;
michael@0 13 }
michael@0 14
michael@0 15 var posts = [];
michael@0 16 posts.push(generateContent(10));
michael@0 17 posts.push(generateContent(250000));
michael@0 18
michael@0 19 // pre-calculated md5sums (in hex) of the above posts
michael@0 20 var md5s = ['f1b708bba17f1ce948dc979f4d7092bc',
michael@0 21 '2ef8d3b6c8f329318eb1a119b12622b6'];
michael@0 22
michael@0 23 var bigListenerData = generateContent(128 * 1024);
michael@0 24 var bigListenerMD5 = '8f607cfdd2c87d6a7eedb657dafbd836';
michael@0 25
michael@0 26 function checkIsSpdy(request) {
michael@0 27 try {
michael@0 28 if (request.getResponseHeader("X-Firefox-Spdy") == "3") {
michael@0 29 if (request.getResponseHeader("X-Connection-Spdy") == "yes") {
michael@0 30 return true;
michael@0 31 }
michael@0 32 return false; // Weird case, but the server disagrees with us
michael@0 33 }
michael@0 34 } catch (e) {
michael@0 35 // Nothing to do here
michael@0 36 }
michael@0 37 return false;
michael@0 38 }
michael@0 39
michael@0 40 var SpdyCheckListener = function() {};
michael@0 41
michael@0 42 SpdyCheckListener.prototype = {
michael@0 43 onStartRequestFired: false,
michael@0 44 onDataAvailableFired: false,
michael@0 45 isSpdyConnection: false,
michael@0 46
michael@0 47 onStartRequest: function testOnStartRequest(request, ctx) {
michael@0 48 this.onStartRequestFired = true;
michael@0 49
michael@0 50 if (!Components.isSuccessCode(request.status))
michael@0 51 do_throw("Channel should have a success code! (" + request.status + ")");
michael@0 52 if (!(request instanceof Components.interfaces.nsIHttpChannel))
michael@0 53 do_throw("Expecting an HTTP channel");
michael@0 54
michael@0 55 do_check_eq(request.responseStatus, 200);
michael@0 56 do_check_eq(request.requestSucceeded, true);
michael@0 57 },
michael@0 58
michael@0 59 onDataAvailable: function testOnDataAvailable(request, ctx, stream, off, cnt) {
michael@0 60 this.onDataAvailableFired = true;
michael@0 61 this.isSpdyConnection = checkIsSpdy(request);
michael@0 62
michael@0 63 read_stream(stream, cnt);
michael@0 64 },
michael@0 65
michael@0 66 onStopRequest: function testOnStopRequest(request, ctx, status) {
michael@0 67 do_check_true(this.onStartRequestFired);
michael@0 68 do_check_true(this.onDataAvailableFired);
michael@0 69 do_check_true(this.isSpdyConnection);
michael@0 70
michael@0 71 run_next_test();
michael@0 72 do_test_finished();
michael@0 73 }
michael@0 74 };
michael@0 75
michael@0 76 /*
michael@0 77 * Support for testing valid multiplexing of streams
michael@0 78 */
michael@0 79
michael@0 80 var multiplexContent = generateContent(30*1024);
michael@0 81 var completed_channels = [];
michael@0 82 function register_completed_channel(listener) {
michael@0 83 completed_channels.push(listener);
michael@0 84 if (completed_channels.length == 2) {
michael@0 85 do_check_neq(completed_channels[0].streamID, completed_channels[1].streamID);
michael@0 86 run_next_test();
michael@0 87 do_test_finished();
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 /* Listener class to control the testing of multiplexing */
michael@0 92 var SpdyMultiplexListener = function() {};
michael@0 93
michael@0 94 SpdyMultiplexListener.prototype = new SpdyCheckListener();
michael@0 95
michael@0 96 SpdyMultiplexListener.prototype.streamID = 0;
michael@0 97 SpdyMultiplexListener.prototype.buffer = "";
michael@0 98
michael@0 99 SpdyMultiplexListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
michael@0 100 this.onDataAvailableFired = true;
michael@0 101 this.isSpdyConnection = checkIsSpdy(request);
michael@0 102 this.streamID = parseInt(request.getResponseHeader("X-Spdy-StreamID"));
michael@0 103 var data = read_stream(stream, cnt);
michael@0 104 this.buffer = this.buffer.concat(data);
michael@0 105 };
michael@0 106
michael@0 107 SpdyMultiplexListener.prototype.onStopRequest = function(request, ctx, status) {
michael@0 108 do_check_true(this.onStartRequestFired);
michael@0 109 do_check_true(this.onDataAvailableFired);
michael@0 110 do_check_true(this.isSpdyConnection);
michael@0 111 do_check_true(this.buffer == multiplexContent);
michael@0 112
michael@0 113 // This is what does most of the hard work for us
michael@0 114 register_completed_channel(this);
michael@0 115 };
michael@0 116
michael@0 117 // Does the appropriate checks for header gatewaying
michael@0 118 var SpdyHeaderListener = function(value) {
michael@0 119 this.value = value
michael@0 120 };
michael@0 121
michael@0 122 SpdyHeaderListener.prototype = new SpdyCheckListener();
michael@0 123 SpdyHeaderListener.prototype.value = "";
michael@0 124
michael@0 125 SpdyHeaderListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
michael@0 126 this.onDataAvailableFired = true;
michael@0 127 this.isSpdyConnection = checkIsSpdy(request);
michael@0 128 do_check_eq(request.getResponseHeader("X-Received-Test-Header"), this.value);
michael@0 129 read_stream(stream, cnt);
michael@0 130 };
michael@0 131
michael@0 132 var SpdyPushListener = function() {};
michael@0 133
michael@0 134 SpdyPushListener.prototype = new SpdyCheckListener();
michael@0 135
michael@0 136 SpdyPushListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
michael@0 137 this.onDataAvailableFired = true;
michael@0 138 this.isSpdyConnection = checkIsSpdy(request);
michael@0 139 if (ctx.originalURI.spec == "https://localhost:4443/push.js" ||
michael@0 140 ctx.originalURI.spec == "https://localhost:4443/push2.js") {
michael@0 141 do_check_eq(request.getResponseHeader("pushed"), "yes");
michael@0 142 }
michael@0 143 read_stream(stream, cnt);
michael@0 144 };
michael@0 145
michael@0 146 // Does the appropriate checks for a large GET response
michael@0 147 var SpdyBigListener = function() {};
michael@0 148
michael@0 149 SpdyBigListener.prototype = new SpdyCheckListener();
michael@0 150 SpdyBigListener.prototype.buffer = "";
michael@0 151
michael@0 152 SpdyBigListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
michael@0 153 this.onDataAvailableFired = true;
michael@0 154 this.isSpdyConnection = checkIsSpdy(request);
michael@0 155 this.buffer = this.buffer.concat(read_stream(stream, cnt));
michael@0 156 // We know the server should send us the same data as our big post will be,
michael@0 157 // so the md5 should be the same
michael@0 158 do_check_eq(bigListenerMD5, request.getResponseHeader("X-Expected-MD5"));
michael@0 159 };
michael@0 160
michael@0 161 SpdyBigListener.prototype.onStopRequest = function(request, ctx, status) {
michael@0 162 do_check_true(this.onStartRequestFired);
michael@0 163 do_check_true(this.onDataAvailableFired);
michael@0 164 do_check_true(this.isSpdyConnection);
michael@0 165
michael@0 166 // Don't want to flood output, so don't use do_check_eq
michael@0 167 do_check_true(this.buffer == bigListenerData);
michael@0 168
michael@0 169 run_next_test();
michael@0 170 do_test_finished();
michael@0 171 };
michael@0 172
michael@0 173 // Does the appropriate checks for POSTs
michael@0 174 var SpdyPostListener = function(expected_md5) {
michael@0 175 this.expected_md5 = expected_md5;
michael@0 176 };
michael@0 177
michael@0 178 SpdyPostListener.prototype = new SpdyCheckListener();
michael@0 179 SpdyPostListener.prototype.expected_md5 = "";
michael@0 180
michael@0 181 SpdyPostListener.prototype.onDataAvailable = function(request, ctx, stream, off, cnt) {
michael@0 182 this.onDataAvailableFired = true;
michael@0 183 this.isSpdyConnection = checkIsSpdy(request);
michael@0 184 read_stream(stream, cnt);
michael@0 185 do_check_eq(this.expected_md5, request.getResponseHeader("X-Calculated-MD5"));
michael@0 186 };
michael@0 187
michael@0 188 function makeChan(url) {
michael@0 189 var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
michael@0 190 var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel);
michael@0 191
michael@0 192 return chan;
michael@0 193 }
michael@0 194
michael@0 195 // Make sure we make a spdy connection and both us and the server mark it as such
michael@0 196 function test_spdy_basic() {
michael@0 197 var chan = makeChan("https://localhost:4443/");
michael@0 198 var listener = new SpdyCheckListener();
michael@0 199 chan.asyncOpen(listener, null);
michael@0 200 }
michael@0 201
michael@0 202 // Support for making sure XHR works over SPDY
michael@0 203 function checkXhr(xhr) {
michael@0 204 if (xhr.readyState != 4) {
michael@0 205 return;
michael@0 206 }
michael@0 207
michael@0 208 do_check_eq(xhr.status, 200);
michael@0 209 do_check_eq(checkIsSpdy(xhr), true);
michael@0 210 run_next_test();
michael@0 211 do_test_finished();
michael@0 212 }
michael@0 213
michael@0 214 // Fires off an XHR request over SPDY
michael@0 215 function test_spdy_xhr() {
michael@0 216 var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
michael@0 217 .createInstance(Ci.nsIXMLHttpRequest);
michael@0 218 req.open("GET", "https://localhost:4443/", true);
michael@0 219 req.addEventListener("readystatechange", function (evt) { checkXhr(req); },
michael@0 220 false);
michael@0 221 req.send(null);
michael@0 222 }
michael@0 223
michael@0 224 // Test to make sure we get multiplexing right
michael@0 225 function test_spdy_multiplex() {
michael@0 226 var chan1 = makeChan("https://localhost:4443/multiplex1");
michael@0 227 var chan2 = makeChan("https://localhost:4443/multiplex2");
michael@0 228 var listener1 = new SpdyMultiplexListener();
michael@0 229 var listener2 = new SpdyMultiplexListener();
michael@0 230 chan1.asyncOpen(listener1, null);
michael@0 231 chan2.asyncOpen(listener2, null);
michael@0 232 }
michael@0 233
michael@0 234 // Test to make sure we gateway non-standard headers properly
michael@0 235 function test_spdy_header() {
michael@0 236 var chan = makeChan("https://localhost:4443/header");
michael@0 237 var hvalue = "Headers are fun";
michael@0 238 var listener = new SpdyHeaderListener(hvalue);
michael@0 239 chan.setRequestHeader("X-Test-Header", hvalue, false);
michael@0 240 chan.asyncOpen(listener, null);
michael@0 241 }
michael@0 242
michael@0 243 function test_spdy_push1() {
michael@0 244 var chan = makeChan("https://localhost:4443/push");
michael@0 245 chan.loadGroup = loadGroup;
michael@0 246 var listener = new SpdyPushListener();
michael@0 247 chan.asyncOpen(listener, chan);
michael@0 248 }
michael@0 249
michael@0 250 function test_spdy_push2() {
michael@0 251 var chan = makeChan("https://localhost:4443/push.js");
michael@0 252 chan.loadGroup = loadGroup;
michael@0 253 var listener = new SpdyPushListener();
michael@0 254 chan.asyncOpen(listener, chan);
michael@0 255 }
michael@0 256
michael@0 257 function test_spdy_push3() {
michael@0 258 var chan = makeChan("https://localhost:4443/push2");
michael@0 259 chan.loadGroup = loadGroup;
michael@0 260 var listener = new SpdyPushListener();
michael@0 261 chan.asyncOpen(listener, chan);
michael@0 262 }
michael@0 263
michael@0 264 function test_spdy_push4() {
michael@0 265 var chan = makeChan("https://localhost:4443/push2.js");
michael@0 266 chan.loadGroup = loadGroup;
michael@0 267 var listener = new SpdyPushListener();
michael@0 268 chan.asyncOpen(listener, chan);
michael@0 269 }
michael@0 270
michael@0 271 // Make sure we handle GETs that cover more than 2 frames properly
michael@0 272 function test_spdy_big() {
michael@0 273 var chan = makeChan("https://localhost:4443/big");
michael@0 274 var listener = new SpdyBigListener();
michael@0 275 chan.asyncOpen(listener, null);
michael@0 276 }
michael@0 277
michael@0 278 // Support for doing a POST
michael@0 279 function do_post(content, chan, listener) {
michael@0 280 var stream = Cc["@mozilla.org/io/string-input-stream;1"]
michael@0 281 .createInstance(Ci.nsIStringInputStream);
michael@0 282 stream.data = content;
michael@0 283
michael@0 284 var uchan = chan.QueryInterface(Ci.nsIUploadChannel);
michael@0 285 uchan.setUploadStream(stream, "text/plain", stream.available());
michael@0 286
michael@0 287 chan.requestMethod = "POST";
michael@0 288
michael@0 289 chan.asyncOpen(listener, null);
michael@0 290 }
michael@0 291
michael@0 292 // Make sure we can do a simple POST
michael@0 293 function test_spdy_post() {
michael@0 294 var chan = makeChan("https://localhost:4443/post");
michael@0 295 var listener = new SpdyPostListener(md5s[0]);
michael@0 296 do_post(posts[0], chan, listener);
michael@0 297 }
michael@0 298
michael@0 299 // Make sure we can do a POST that covers more than 2 frames
michael@0 300 function test_spdy_post_big() {
michael@0 301 var chan = makeChan("https://localhost:4443/post");
michael@0 302 var listener = new SpdyPostListener(md5s[1]);
michael@0 303 do_post(posts[1], chan, listener);
michael@0 304 }
michael@0 305
michael@0 306 // hack - the header test resets the multiplex object on the server,
michael@0 307 // so make sure header is always run before the multiplex test.
michael@0 308 //
michael@0 309 // make sure post_big runs first to test race condition in restarting
michael@0 310 // a stalled stream when a SETTINGS frame arrives
michael@0 311 var tests = [ test_spdy_post_big
michael@0 312 , test_spdy_basic
michael@0 313 , test_spdy_push1
michael@0 314 , test_spdy_push2
michael@0 315 , test_spdy_push3
michael@0 316 , test_spdy_push4
michael@0 317 , test_spdy_xhr
michael@0 318 , test_spdy_header
michael@0 319 , test_spdy_multiplex
michael@0 320 , test_spdy_big
michael@0 321 , test_spdy_post
michael@0 322 ];
michael@0 323 var current_test = 0;
michael@0 324
michael@0 325 function run_next_test() {
michael@0 326 if (current_test < tests.length) {
michael@0 327 tests[current_test]();
michael@0 328 current_test++;
michael@0 329 do_test_pending();
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 // Support for making sure we can talk to the invalid cert the server presents
michael@0 334 var CertOverrideListener = function(host, port, bits) {
michael@0 335 this.host = host;
michael@0 336 if (port) {
michael@0 337 this.port = port;
michael@0 338 }
michael@0 339 this.bits = bits;
michael@0 340 };
michael@0 341
michael@0 342 CertOverrideListener.prototype = {
michael@0 343 host: null,
michael@0 344 port: -1,
michael@0 345 bits: null,
michael@0 346
michael@0 347 getInterface: function(aIID) {
michael@0 348 return this.QueryInterface(aIID);
michael@0 349 },
michael@0 350
michael@0 351 QueryInterface: function(aIID) {
michael@0 352 if (aIID.equals(Ci.nsIBadCertListener2) ||
michael@0 353 aIID.equals(Ci.nsIInterfaceRequestor) ||
michael@0 354 aIID.equals(Ci.nsISupports))
michael@0 355 return this;
michael@0 356 throw Components.results.NS_ERROR_NO_INTERFACE;
michael@0 357 },
michael@0 358
michael@0 359 notifyCertProblem: function(socketInfo, sslStatus, targetHost) {
michael@0 360 var cert = sslStatus.QueryInterface(Ci.nsISSLStatus).serverCert;
michael@0 361 var cos = Cc["@mozilla.org/security/certoverride;1"].
michael@0 362 getService(Ci.nsICertOverrideService);
michael@0 363 cos.rememberValidityOverride(this.host, this.port, cert, this.bits, false);
michael@0 364 return true;
michael@0 365 },
michael@0 366 };
michael@0 367
michael@0 368 function addCertOverride(host, port, bits) {
michael@0 369 var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
michael@0 370 .createInstance(Ci.nsIXMLHttpRequest);
michael@0 371 try {
michael@0 372 var url;
michael@0 373 if (port) {
michael@0 374 url = "https://" + host + ":" + port + "/";
michael@0 375 } else {
michael@0 376 url = "https://" + host + "/";
michael@0 377 }
michael@0 378 req.open("GET", url, false);
michael@0 379 req.channel.notificationCallbacks = new CertOverrideListener(host, port, bits);
michael@0 380 req.send(null);
michael@0 381 } catch (e) {
michael@0 382 // This will fail since the server is not trusted yet
michael@0 383 }
michael@0 384 }
michael@0 385
michael@0 386 var prefs;
michael@0 387 var spdypref;
michael@0 388 var spdy3pref;
michael@0 389 var spdypush;
michael@0 390
michael@0 391 var loadGroup;
michael@0 392
michael@0 393 function resetPrefs() {
michael@0 394 prefs.setBoolPref("network.http.spdy.enabled", spdypref);
michael@0 395 prefs.setBoolPref("network.http.spdy.enabled.v3", spdy3pref);
michael@0 396 prefs.setBoolPref("network.http.spdy.allow-push", spdypush);
michael@0 397 }
michael@0 398
michael@0 399 function run_test() {
michael@0 400 // Set to allow the cert presented by our SPDY server
michael@0 401 do_get_profile();
michael@0 402 var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
michael@0 403 var oldPref = prefs.getIntPref("network.http.speculative-parallel-limit");
michael@0 404 prefs.setIntPref("network.http.speculative-parallel-limit", 0);
michael@0 405
michael@0 406 addCertOverride("localhost", 4443,
michael@0 407 Ci.nsICertOverrideService.ERROR_UNTRUSTED |
michael@0 408 Ci.nsICertOverrideService.ERROR_MISMATCH |
michael@0 409 Ci.nsICertOverrideService.ERROR_TIME);
michael@0 410
michael@0 411 prefs.setIntPref("network.http.speculative-parallel-limit", oldPref);
michael@0 412
michael@0 413 // Enable all versions of spdy to see that we auto negotiate spdy/3
michael@0 414 spdypref = prefs.getBoolPref("network.http.spdy.enabled");
michael@0 415 spdy3pref = prefs.getBoolPref("network.http.spdy.enabled.v3");
michael@0 416 spdypush = prefs.getBoolPref("network.http.spdy.allow-push");
michael@0 417 prefs.setBoolPref("network.http.spdy.enabled", true);
michael@0 418 prefs.setBoolPref("network.http.spdy.enabled.v3", true);
michael@0 419 prefs.setBoolPref("network.http.spdy.allow-push", true);
michael@0 420
michael@0 421 loadGroup = Cc["@mozilla.org/network/load-group;1"].createInstance(Ci.nsILoadGroup);
michael@0 422
michael@0 423 // And make go!
michael@0 424 run_next_test();
michael@0 425 }

mercurial