netwerk/test/unit/test_speculative_connect.js

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

     1 /* -*- Mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* vim: set ts=4 sts=4 et sw=4 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 const CC = Components.Constructor;
     8 const ServerSocket = CC("@mozilla.org/network/server-socket;1",
     9                         "nsIServerSocket",
    10                         "init");
    11 var serv;
    12 var ios;
    14 /** Example local IP addresses (literal IP address hostname).
    15  *
    16  * Note: for IPv6 Unique Local and Link Local, a wider range of addresses is
    17  * set aside than those most commonly used. Technically, link local addresses
    18  * include those beginning with fe80:: through febf::, although in practise
    19  * only fe80:: is used. Necko code blocks speculative connections for the wider
    20  * range; hence, this test considers that range too.
    21  */
    22 var localIPv4Literals =
    23     [ // IPv4 RFC1918 \
    24       "10.0.0.1", "10.10.10.10", "10.255.255.255",         // 10/8
    25       "172.16.0.1", "172.23.172.12", "172.31.255.255",     // 172.16/20
    26       "192.168.0.1", "192.168.192.168", "192.168.255.255", // 192.168/16
    27       // IPv4 Link Local
    28       "169.254.0.1", "169.254.192.154", "169.254.255.255"  // 169.254/16
    29     ];
    30 var localIPv6Literals =
    31     [ // IPv6 Unique Local fc00::/7
    32       "fc00::1", "fdfe:dcba:9876:abcd:ef01:2345:6789:abcd",
    33       "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
    34       // IPv6 Link Local fe80::/10
    35       "fe80::1", "fe80::abcd:ef01:2345:6789",
    36       "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
    37     ];
    38 var localIPLiterals = localIPv4Literals.concat(localIPv6Literals);
    40 /** Test function list and descriptions.
    41  */
    42 var testList =
    43     [ test_speculative_connect,
    44       test_hostnames_resolving_to_local_addresses,
    45       test_proxies_with_local_addresses
    46     ];
    48 var testDescription =
    49     [ "Expect pass with localhost",
    50       "Expect failure with resolved local IPs",
    51       "Expect failure for proxies with local IPs"
    52     ];
    54 var testIdx = 0;
    55 var hostIdx = 0;
    58 /** TestServer
    59  *
    60  * Implements nsIServerSocket for test_speculative_connect.
    61  */
    62 function TestServer() {
    63     this.listener = ServerSocket(-1, true, -1);
    64     this.listener.asyncListen(this);
    65 }
    67 TestServer.prototype = {
    68     QueryInterface: function(iid) {
    69         if (iid.equals(Ci.nsIServerSocket) ||
    70             iid.equals(Ci.nsISupports))
    71             return this;
    72         throw Cr.NS_ERROR_NO_INTERFACE;
    73     },
    74     onSocketAccepted: function(socket, trans) {
    75         try { this.listener.close(); } catch(e) {}
    76         do_check_true(true);
    77         next_test();
    78     },
    80     onStopListening: function(socket) {}
    81 };
    83 /** TestOutputStreamCallback
    84  *
    85  * Implements nsIOutputStreamCallback for socket layer tests.
    86  */
    87 function TestOutputStreamCallback(transport, hostname, proxied, expectSuccess, next) {
    88     this.transport = transport;
    89     this.hostname = hostname;
    90     this.proxied = proxied;
    91     this.expectSuccess = expectSuccess;
    92     this.next = next;
    93     this.dummyContent = "Dummy content";
    94 }
    96 TestOutputStreamCallback.prototype = {
    97     QueryInterface: function(iid) {
    98         if (iid.equals(Ci.nsIOutputStreamCallback) ||
    99             iid.equals(Ci.nsISupports))
   100             return this;
   101         throw Cr.NS_ERROR_NO_INTERFACE;
   102     },
   103     onOutputStreamReady: function(stream) {
   104         do_check_neq(typeof(stream), undefined);
   105         try {
   106             stream.write(this.dummyContent, this.dummyContent.length);
   107         } catch (e) {
   108             // Spec Connect FAILED.
   109             do_check_instanceof(e, Ci.nsIException);
   110             if (this.expectSuccess) {
   111                 // We may expect success, but the address could be unreachable
   112                 // in the test environment, so expect errors.
   113                 if (this.proxied) {
   114                     do_check_true(e.result == Cr.NS_ERROR_NET_TIMEOUT ||
   115                                   e.result == Cr.NS_ERROR_PROXY_CONNECTION_REFUSED);
   116                 } else {
   117                     do_check_true(e.result == Cr.NS_ERROR_NET_TIMEOUT ||
   118                                   e.result == Cr.NS_ERROR_CONNECTION_REFUSED);
   119                 }
   120             } else {
   121                 // A refusal to connect speculatively should throw an error.
   122                 do_check_eq(e.result, Cr.NS_ERROR_CONNECTION_REFUSED);
   123             }
   124             this.transport.close(Cr.NS_BINDING_ABORTED);
   125             this.next();
   126             return;
   127         }
   128         // Spec Connect SUCCEEDED.
   129         if (this.expectSuccess) {
   130             do_check_true(true, "Success for " + this.hostname);
   131         } else {
   132             do_throw("Speculative Connect should have failed for " +
   133                      this.hostname);
   134         }
   135         this.transport.close(Cr.NS_BINDING_ABORTED);
   136         this.next();
   137     }
   138 };
   140 /** test_speculative_connect
   141  *
   142  * Tests a basic positive case using nsIOService.SpeculativeConnect:
   143  * connecting to localhost.
   144  */
   145 function test_speculative_connect() {
   146     serv = new TestServer();
   147     var URI = ios.newURI("http://localhost:" + serv.listener.port + "/just/a/test", null, null);
   148     ios.QueryInterface(Ci.nsISpeculativeConnect)
   149         .speculativeConnect(URI, null);
   150 }
   152 /* Speculative connections should not be allowed for hosts with local IP
   153  * addresses (Bug 853423). That list includes:
   154  *  -- IPv4 RFC1918 and Link Local Addresses.
   155  *  -- IPv6 Unique and Link Local Addresses.
   156  *
   157  * Two tests are required:
   158  *  1. Verify IP Literals passed to the SpeculativeConnect API.
   159  *  2. Verify hostnames that need to be resolved at the socket layer.
   160  */
   162 /** test_hostnames_resolving_to_addresses
   163  *
   164  * Common test function for resolved hostnames. Takes a list of hosts, a
   165  * boolean to determine if the test is expected to succeed or fail, and a
   166  * function to call the next test case.
   167  */
   168 function test_hostnames_resolving_to_addresses(host, expectSuccess, next) {
   169     do_print(host);
   170     var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
   171               .getService(Ci.nsISocketTransportService);
   172     do_check_neq(typeof(sts), undefined);
   173     var transport = sts.createTransport(null, 0, host, 80, null);
   174     do_check_neq(typeof(transport), undefined);
   176     transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
   177     transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 1);
   178     transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 1);
   179     do_check_eq(1, transport.getTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT));
   181     var outStream = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED,0,0);
   182     do_check_neq(typeof(outStream), undefined);
   184     var callback = new TestOutputStreamCallback(transport, host, false,
   185                                                 expectSuccess,
   186                                                 next);
   187     do_check_neq(typeof(callback), undefined);
   189     // Need to get main thread pointer to ensure nsSocketTransport::AsyncWait
   190     // adds callback to nsOutputStreamReadyEvent on main thread, and doesn't
   191     // addref off the main thread.
   192     var gThreadManager = Cc["@mozilla.org/thread-manager;1"]
   193     .getService(Ci.nsIThreadManager);
   194     var mainThread = gThreadManager.currentThread;
   196     try {
   197         outStream.QueryInterface(Ci.nsIAsyncOutputStream)
   198                  .asyncWait(callback, 0, 0, mainThread);
   199     } catch (e) {
   200         do_throw("asyncWait should not fail!");
   201     }
   202 }
   204 /**
   205  * test_hostnames_resolving_to_local_addresses
   206  *
   207  * Creates an nsISocketTransport and simulates a speculative connect request
   208  * for a hostname that resolves to a local IP address.
   209  * Runs asynchronously; on test success (i.e. failure to connect), the callback
   210  * will call this function again until all hostnames in the test list are done.
   211  *
   212  * Note: This test also uses an IP literal for the hostname. This should be ok,
   213  * as the socket layer will ask for the hostname to be resolved anyway, and DNS
   214  * code should return a numerical version of the address internally.
   215  */
   216 function test_hostnames_resolving_to_local_addresses() {
   217     if (hostIdx >= localIPLiterals.length) {
   218         // No more local IP addresses; move on.
   219         next_test();
   220         return;
   221     }
   222     var host = localIPLiterals[hostIdx++];
   223     // Test another local IP address when the current one is done.
   224     var next = test_hostnames_resolving_to_local_addresses;
   225     test_hostnames_resolving_to_addresses(host, false, next);
   226 }
   228 /** test_speculative_connect_with_host_list
   229  *
   230  * Common test function for resolved proxy hosts. Takes a list of hosts, a
   231  * boolean to determine if the test is expected to succeed or fail, and a
   232  * function to call the next test case.
   233  */
   234 function test_proxies(proxyHost, expectSuccess, next) {
   235     do_print("Proxy: " + proxyHost);
   236     var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
   237               .getService(Ci.nsISocketTransportService);
   238     do_check_neq(typeof(sts), undefined);
   239     var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"]
   240               .getService();
   241     do_check_neq(typeof(pps), undefined);
   243     var proxyInfo = pps.newProxyInfo("http", proxyHost, 8080, 0, 1, null);
   244     do_check_neq(typeof(proxyInfo), undefined);
   246     var transport = sts.createTransport(null, 0, "dummyHost", 80, proxyInfo);
   247     do_check_neq(typeof(transport), undefined);
   249     transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
   251     transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 1);
   252     do_check_eq(1, transport.getTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT));
   253     transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 1);
   255     var outStream = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED,0,0);
   256     do_check_neq(typeof(outStream), undefined);
   258     var callback = new TestOutputStreamCallback(transport, proxyHost, true,
   259                                                 expectSuccess,
   260                                                 next);
   261     do_check_neq(typeof(callback), undefined);
   263     // Need to get main thread pointer to ensure nsSocketTransport::AsyncWait
   264     // adds callback to nsOutputStreamReadyEvent on main thread, and doesn't
   265     // addref off the main thread.
   266     var gThreadManager = Cc["@mozilla.org/thread-manager;1"]
   267     .getService(Ci.nsIThreadManager);
   268     var mainThread = gThreadManager.currentThread;
   270     try {
   271         outStream.QueryInterface(Ci.nsIAsyncOutputStream)
   272                  .asyncWait(callback, 0, 0, mainThread);
   273     } catch (e) {
   274         do_throw("asyncWait should not fail!");
   275     }
   276 }
   278 /**
   279  * test_proxies_with_local_addresses
   280  *
   281  * Creates an nsISocketTransport and simulates a speculative connect request
   282  * for a proxy that resolves to a local IP address.
   283  * Runs asynchronously; on test success (i.e. failure to connect), the callback
   284  * will call this function again until all proxies in the test list are done.
   285  *
   286  * Note: This test also uses an IP literal for the proxy. This should be ok,
   287  * as the socket layer will ask for the proxy to be resolved anyway, and DNS
   288  * code should return a numerical version of the address internally.
   289  */
   290 function test_proxies_with_local_addresses() {
   291     if (hostIdx >= localIPLiterals.length) {
   292         // No more local IP addresses; move on.
   293         next_test();
   294         return;
   295     }
   296     var host = localIPLiterals[hostIdx++];
   297     // Test another local IP address when the current one is done.
   298     var next = test_proxies_with_local_addresses;
   299     test_proxies(host, false, next);
   300 }
   302 /** next_test
   303  *
   304  * Calls the next test in testList. Each test is responsible for calling this
   305  * function when its test cases are complete.
   306  */
   307 function next_test() {
   308     if (testIdx >= testList.length) {
   309         // No more tests; we're done.
   310         do_test_finished();
   311         return;
   312     }
   313     do_print("SpeculativeConnect: " + testDescription[testIdx]);
   314     hostIdx = 0;
   315     // Start next test in list.
   316     testList[testIdx++]();
   317 }
   319 /** run_test
   320  *
   321  * Main entry function for test execution.
   322  */
   323 function run_test() {
   324     ios = Cc["@mozilla.org/network/io-service;1"]
   325         .getService(Ci.nsIIOService);
   327     do_test_pending();
   328     next_test();
   329 }

mercurial