bug 640003 - websockets, fixup tests for new server r=smaug r=biesi
authorPatrick McManus <mcmanus@ducksong.com>
Sat, 21 May 2011 21:27:52 -0400
changeset 69861 edfde66134a66c36412aafea42df8537ed3316d8
parent 69860 40b8f77317133ce5da7a4386729a00a037f25785
child 69862 1a2f85fcf598098d15645d6204994b9575a1377c
push id20124
push usermcmanus@ducksong.com
push dateSun, 22 May 2011 02:11:09 +0000
treeherdermozilla-central@9c8537aa965a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, biesi
bugs640003
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 640003 - websockets, fixup tests for new server r=smaug r=biesi
build/automation.py.in
content/base/test/file_websocket_wsh.py
content/base/test/file_ws_basic_tests_wsh.py
content/base/test/test_websocket.html
content/base/test/test_websocket_hello.html
content/base/test/test_ws_basic_tests.html
modules/libpref/src/init/all.js
testing/mochitest/ssltunnel/ssltunnel.cpp
toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_603750_websocket.js
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -436,30 +436,33 @@ function FindProxyForURL(url, host)
                          '(.*?)' +
                          '(?::(\\\\\\\\d+))?/');
   var matches = regex.exec(url);
   if (!matches)
     return 'DIRECT';
   var isHttp = matches[1] == 'http';
   var isHttps = matches[1] == 'https';
   var isWebSocket = matches[1] == 'ws';
+  var isWebSocketSSL = matches[1] == 'wss';
   if (!matches[3])
   {
     if (isHttp | isWebSocket) matches[3] = '80';
-    if (isHttps) matches[3] = '443';
+    if (isHttps | isWebSocketSSL) matches[3] = '443';
   }
   if (isWebSocket)
     matches[1] = 'http';
+  if (isWebSocketSSL)
+    matches[1] = 'https';
 
   var origin = matches[1] + '://' + matches[2] + ':' + matches[3];
   if (origins.indexOf(origin) < 0)
     return 'DIRECT';
   if (isHttp)
     return 'PROXY %(remote)s:%(httpport)s';
-  if (isHttps || isWebSocket)
+  if (isHttps || isWebSocket || isWebSocketSSL)
     return 'PROXY %(remote)s:%(sslport)s';
   return 'DIRECT';
 }""" % { "origins": origins,
          "remote":  self.webServer,
          "httpport":self.httpPort,
          "sslport": self.sslPort }
       pacURL = "".join(pacURL.splitlines())
 
--- a/content/base/test/file_websocket_wsh.py
+++ b/content/base/test/file_websocket_wsh.py
@@ -1,16 +1,19 @@
 from mod_pywebsocket import msgutil
 
 import time
 import sys
 
 # see the list of tests in test_websocket.html
 
 def web_socket_do_extra_handshake(request):
+  # must set request.ws_protocol to the selected version from ws_requested_protocols
+  request.ws_protocol = request.ws_requested_protocols[0]
+
   if request.ws_protocol == "test 2.1":
     time.sleep(5)
     pass
   elif request.ws_protocol == "test 9":
     time.sleep(5)
     pass
   elif request.ws_protocol == "test 10":
     time.sleep(5)
@@ -37,16 +40,17 @@ def web_socket_transfer_data(request):
     resp = "wrong message"
     if msgutil.receive_message(request) == "3":
       resp = "4"
     msgutil.send_message(request, resp.decode('utf-8'))
     resp = "wrong message"
     if msgutil.receive_message(request) == "5":
       resp = "あいうえお"
     msgutil.send_message(request, resp.decode('utf-8'))
+    msgutil.close_connection(request)
   elif request.ws_protocol == "test 7":
     try:
       while not request.client_terminated:
         msgutil.receive_message(request)
     except msgutil.ConnectionTerminatedException, e:
       pass
     msgutil.send_message(request, "server data")
     msgutil.send_message(request, "server data")
@@ -57,24 +61,27 @@ def web_socket_transfer_data(request):
     msgutil.close_connection(request, True)
   elif request.ws_protocol == "test 10":
     msgutil.close_connection(request)
   elif request.ws_protocol == "test 11":
     resp = "wrong message"
     if msgutil.receive_message(request) == "client data":
       resp = "server data"
     msgutil.send_message(request, resp.decode('utf-8'))
+    msgutil.close_connection(request)
+  elif request.ws_protocol == "test 12":
+    msgutil.close_connection(request)
   elif request.ws_protocol == "test 13":
     # first one binary message containing the byte 0x61 ('a')
     request.connection.write('\xff\x01\x61')
     # after a bad utf8 message
     request.connection.write('\x01\x61\xff')
     msgutil.close_connection(request)
   elif request.ws_protocol == "test 14":
-    request.connection.write('\xff\x00')
+    msgutil.close_connection(request)
     msgutil.send_message(request, "server data")
   elif request.ws_protocol == "test 15":
     msgutil.close_connection(request, True)
     return
   elif request.ws_protocol == "test 17" or request.ws_protocol == "test 21":
     time.sleep(5)
     resp = "wrong message"
     if msgutil.receive_message(request) == "client data":
--- a/content/base/test/file_ws_basic_tests_wsh.py
+++ b/content/base/test/file_ws_basic_tests_wsh.py
@@ -1,11 +1,14 @@
 from mod_pywebsocket import msgutil
 
 def web_socket_do_extra_handshake(request):
+  # must set request.ws_protocol to the selected version from ws_requested_protocols
+  request.ws_protocol = request.ws_requested_protocols[0]
+
   if (request.ws_protocol == 'error'):
       raise ValueError('Error')
   pass
 
 def web_socket_transfer_data(request):
   while True:
     line = msgutil.receive_message(request)
     if line == 'protocol':
--- a/content/base/test/test_websocket.html
+++ b/content/base/test/test_websocket.html
@@ -46,17 +46,16 @@
  */
 
 var first_test = 1;
 var last_test = 22;
 
 var current_test = first_test;
 
 var timeoutToAbortTest = 60000;
-var timeoutToOpenWS = 25000;
 var all_ws = [];
 
 function shouldNotOpen(e)
 {
   var ws = e.target;
   ok(false, "onopen shouldn't be called on test " + ws._testNumber + "!");
 }
 
@@ -259,40 +258,49 @@ function test6()
   var counter = 1;
   ws.onopen = function()
   {
     ws.send(counter);
   }
   ws.onmessage = function(e)
   {
     if (counter == 5) {
-      ok(e.data == "あいうえお");
+      ok(e.data == "あいうえお", "test 6 counter 5 data ok");
       ws.close();
       doTest(7);
     } else {
       ok(e.data == counter+1, "bad counter");
       counter += 2;
       ws.send(counter);
     }
   }
   ws.onclose = shouldCloseCleanly;
 }
 
 function test7()
 {
-  var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 7");
-  ws.onopen = function()
-  {
-    ws.close();
-  }
-  ws.onclose = function(e)
-  {
-    shouldCloseNotCleanly(e);
-    doTest(8);
-  };
+// with pywebsockets for -06 ths test no longer does anything useful
+// as the server handles the receipt of the close event directly, not
+// as part of the wsh - so we cannot fake the non-clean close which is
+// what we're trying to do here.
+
+  ok(true, "test disabled");
+  current_test++;
+  doTest(8);
+
+//  var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 7");
+//  ws.onopen = function()
+//  {
+//    ws.close();
+//  }
+//  ws.onclose = function(e)
+//  {
+//    shouldCloseNotCleanly(e);
+//    doTest(8);
+//  };
 }
 
 function test8()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 8");
   ws.onopen = function()
   {
     ws.close();
@@ -333,31 +341,34 @@ function test10()
   {
     doTest(11);
   }
 }
 
 function test11()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 11");
-  ok(ws.readyState == 0, "bad readyState in test 11!");
+  ok(ws.readyState == 0, "create bad readyState in test 11!");
   ws.onopen = function()
   {
-    ok(ws.readyState == 1, "bad readyState in test 11!");
+    ok(ws.readyState == 1, "open bad readyState in test 11!");
     ws.send("client data");
   }
   ws.onmessage = function(e)
   {
     ok(e.data == "server data", "bad received message in test 11!");
     ws.close();
-    ok(ws.readyState == 2, "bad readyState in test 11!");
+
+// this ok() is disabled due to a race condition - it state may have
+// advanced through 2 (closing) and into 3 (closed) before it is evald
+//    ok(ws.readyState == 2, "onmessage bad readyState in test 11!");
   }
   ws.onclose = function(e)
   {
-    ok(ws.readyState == 3, "bad readyState in test 11!");
+    ok(ws.readyState == 3, "onclose bad readyState in test 11!");
     shouldCloseCleanly(e);
     doTest(12);
   }
 }
 
 function test12()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 12");
@@ -367,33 +378,44 @@ function test12()
       // send an unpaired surrogate
       ws.send(String.fromCharCode(0xD800));
       ok(false, "couldn't send an unpaired surrogate!");
     }
     catch (e) {
       ok(true, "couldn't send an unpaired surrogate!");
     }
     ws.close();
+
+// there isnt really a server implementation of test 12, so just
+// ignore an error
+    ws.onerror = function()
+    {
+    }
+
     doTest(13);
   };
 }
 
 function test13()
 {
+    // previous versions of this test counted the number of protocol errors returned, but the 
+    // protocol stack typically closes down after reporting a protocol level error - trying
+    // to resync is too dangerous
+
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 13");
   ws._timesCalledOnError = 0;
   ws.onerror = function()
   {
     ws._timesCalledOnError++;
-    if (ws._timesCalledOnError == 2) {
-      ok(true, "test 13 succeeded");
-      doTest(14);
-    }
   }
-  ws.onclose = shouldCloseCleanly;
+  ws.onclose = function(e)
+  {
+    ok(ws._timesCalledOnError > 0, "no error events");
+    doTest(14);
+  }
 }
 
 function test14()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 14");
   ws.onmessage = function()
   {
     ok(false, "shouldn't received message after the server sent the close frame");
@@ -408,32 +430,44 @@ function test14()
 function test15()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 15");
   ws.onclose = function(e)
   {
     shouldCloseNotCleanly(e);
     doTest(16);
   };
+
+  // termination of the connection might cause an error event if it happens in OPEN
+  ws.onerror = function()
+  {
+  }
+
 }
 
 function test16()
 {
   var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 16");
   ws.onopen = function()
   {
     ws.close();
     ok(!ws.send("client data"), "shouldn't send message after calling close()");
     doTest(17);
   }
   ws.onmessage = function()
   {
     ok(false, "shouldn't send message after calling close()");
   }
-  ws.onclose = shouldCloseCleanly;
+
+  ws.onerror = function()
+  {
+  }
+  ws.onclose = function()
+  {
+  }
 }
 
 var status_test17 = "not started";
 
 window._test17 = function()
 {
   var local_ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test 17");
   local_ws._testNumber = "local17";
@@ -588,41 +622,29 @@ function test22()
   ws.onopen = shouldNotOpen;
   ws.onclose = function(e)
   {
     shouldCloseNotCleanly(e);
     doTest(23);
   };
 }
 
-var domBranch;
-var oldPrefVal;
-
 function finishWSTest()
 {
   for (i = 0; i < all_ws.length; ++i) {
     if (all_ws[i] != shouldNotReceiveCloseEvent &&
         !all_ws[i]._receivedCloseEvent) {
       ok(false, "didn't called close on test " + all_ws[i]._testNumber + "!");
     }
   }
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  domBranch.setBoolPref("override-security-block", oldPrefVal);
   SimpleTest.finish();
 }
 
 function testWebSocket ()
 {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
   doTest(first_test);
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 
--- a/content/base/test/test_websocket_hello.html
+++ b/content/base/test/test_websocket_hello.html
@@ -12,48 +12,32 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=472529">Mozilla Bug </a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var ws;
-var oldPrefVal;
-var domBranch;
-
-function finishWSTest() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    domBranch.setBoolPref("override-security-block", oldPrefVal);
-    SimpleTest.finish();
-}
 
 function testWebSocket () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
-
   ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_websocket_hello");
   ws.onopen = function(e) {
     ws.send("data");
   }
   ws.onclose = function(e) {
   }
   ws.onerror = function(e) {
     ok(false, "onerror called!");
-    finishWSTest();
+    SimpleTest.finish();
   }
   ws.onmessage = function(e) {
     is(e.data, "Hello world!", "Wrong data");
     ws.close();
-    finishWSTest();
+    SimpleTest.finish();
   }
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 <div>
--- a/content/base/test/test_ws_basic_tests.html
+++ b/content/base/test/test_ws_basic_tests.html
@@ -12,45 +12,33 @@
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=472529">Mozilla Bug </a>
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 var ws;
-var oldPrefVal;
-var domBranch;
 
 var params = ["protocol", "resource", "origin", "end"];
 var results = ["test", "/tests/content/base/test/file_ws_basic_tests", "http://mochi.test:8888", "end"];
 
 function forcegc(){
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   Components.utils.forceGC();
   var wu =  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIDOMWindowUtils);
   wu.garbageCollect();
 }
 
 function finishWSTest() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    domBranch.setBoolPref("override-security-block", oldPrefVal);
     SimpleTest.finish();
 }
 
 function testWebSocket () {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var prefService =
-      Components.classes["@mozilla.org/preferences-service;1"]
-      .getService(Components.interfaces.nsIPrefService);
-  domBranch = prefService.getBranch("network.websocket.");
-  oldPrefVal = domBranch.getBoolPref("override-security-block");
-  domBranch.setBoolPref("override-security-block", true);
-
   var url = "ws://mochi.test:8888/tests/content/base/test/file_ws_basic_tests";
   ws = new WebSocket("ws://mochi.test:8888/tests/content/base/test/file_ws_basic_tests", "test");
   is(ws.url, url, "Wrong Websocket.url!");
   ws.onopen = function(e) {
     for (var i = 0; i < params.length; ++i) {
       document.getElementById('log').textContent += "sending " + params[i] + "\n";
       ws.send(params[i]);
     }
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -776,21 +776,16 @@ pref("network.http.connection-retry-time
 // Section 4.8 "High-Throughput Data Service Class", and 80 (0x50, or AF22)
 // per Section 4.7 "Low-Latency Data Service Class".
 pref("network.ftp.data.qos", 0);
 pref("network.ftp.control.qos", 0);
 
 // </http>
 
 // <ws>: WebSocket
-// The -76 websocket network protocol may be subject to HTTP cache poisoning
-// attacks. Until there is a secure open standard available and implemented
-// in necko the override-security-block preference must be set to true before
-// the normal enabled preference is considered. Bug 616733
-pref("network.websocket.override-security-block", false);
 pref("network.websocket.enabled", true);
 // </ws>
 
 // If false, remote JAR files that are served with a content type other than
 // application/java-archive or application/x-jar will not be opened
 // by the jar channel.
 pref("network.jar.open-unsafe-types", false);
 
--- a/testing/mochitest/ssltunnel/ssltunnel.cpp
+++ b/testing/mochitest/ssltunnel/ssltunnel.cpp
@@ -422,17 +422,17 @@ bool ConfigureSSLServerSocket(PRFileDesc
   }
 
   SSL_ResetHandshake(ssl_socket, PR_TRUE);
 
   return true;
 }
 
 /**
- * This function examines the buffer for a S5ec-WebSocket-Location: field, 
+ * This function examines the buffer for a Sec-WebSocket-Location: field, 
  * and if it's present, it replaces the hostname in that field with the
  * value in the server's original_host field.  This function works
  * in the reverse direction as AdjustWebSocketHost(), replacing the real
  * hostname of a response with the potentially fake hostname that is expected
  * by the browser (e.g., mochi.test).
  *
  * @return true if the header was adjusted successfully, or not found, false
  * if the header is present but the url is not, which should indicate
@@ -495,16 +495,18 @@ bool AdjustWebSocketHost(relayBuffer& bu
 
   // Verify this is a WebSocket header.
   char* h1 = strstr(buffer.bufferhead, HEADER_UPGRADE);
   if (!h1)
     return false;
   h1 += strlen(HEADER_UPGRADE);
   h1 += strspn(h1, " \t");
   char* h2 = strstr(h1, "WebSocket\r\n");
+  if (!h2) h2 = strstr(h1, "websocket\r\n");
+  if (!h2) h2 = strstr(h1, "Websocket\r\n");
   if (!h2)
     return false;
 
   char* host = strstr(buffer.bufferhead, HEADER_HOST);
   if (!host)
     return false;
   // advance pointer to beginning of hostname
   host += strlen(HEADER_HOST);
--- a/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_603750_websocket.js
+++ b/toolkit/components/console/hudservice/tests/browser/browser_webconsole_bug_603750_websocket.js
@@ -9,17 +9,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 const TEST_URI = "http://example.com/browser/toolkit/components/console/hudservice/tests/browser/test-bug-603750-websocket.html";
 const pref_ws = "network.websocket.enabled";
 const pref_block = "network.websocket.override-security-block";
 
 let errors = 0;
 let lastWindowId = 0;
-let oldPref_ws, oldPref_block;
+let oldPref_ws;
 
 let TestObserver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
 
   observe: function test_observe(aSubject)
   {
     if (!(aSubject instanceof Ci.nsIScriptError) ||
         !(aSubject instanceof Ci.nsIScriptError2)) {
@@ -58,23 +58,20 @@ function performTest() {
   let textContent = hud.outputNode.textContent;
   isnot(textContent.indexOf("ws://0.0.0.0:81"), -1,
         "first error message found");
   isnot(textContent.indexOf("ws://0.0.0.0:82"), -1,
         "second error message found");
 
   Services.console.unregisterListener(TestObserver);
   Services.prefs.setBoolPref(pref_ws, oldPref_ws);
-  Services.prefs.setBoolPref(pref_block, oldPref_block);
   finishTest();
 }
 
 function test() {
   oldPref_ws = Services.prefs.getBoolPref(pref_ws);
-  oldPref_block = Services.prefs.getBoolPref(pref_block);
 
   Services.prefs.setBoolPref(pref_ws, true);
-  Services.prefs.setBoolPref(pref_block, true);
 
   addTab("data:text/html,Web Console test for bug 603750: Web Socket errors");
   browser.addEventListener("load", tabLoad, true);
 }