netwerk/test/unit/test_plaintext_sniff.js

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 // Test the plaintext-or-binary sniffer
     3 Cu.import("resource://testing-common/httpd.js");
     5 // List of Content-Type headers to test.  For each header we have an array.
     6 // The first element in the array is the Content-Type header string.  The
     7 // second element in the array is a boolean indicating whether we allow
     8 // sniffing for that type.
     9 var contentTypeHeaderList =
    10 [
    11  [ "text/plain", true ],
    12  [ "text/plain; charset=ISO-8859-1", true ],
    13  [ "text/plain; charset=iso-8859-1", true ],
    14  [ "text/plain; charset=UTF-8", true ],
    15  [ "text/plain; charset=unknown", false ],
    16  [ "text/plain; param", false ],
    17  [ "text/plain; charset=ISO-8859-1; param", false ],
    18  [ "text/plain; charset=iso-8859-1; param", false ],
    19  [ "text/plain; charset=UTF-8; param", false ],
    20  [ "text/plain; charset=utf-8", false ],
    21  [ "text/plain; charset=utf8", false ],
    22  [ "text/plain; charset=UTF8", false ],
    23  [ "text/plain; charset=iSo-8859-1", false ]
    24 ];
    26 // List of response bodies to test.  For each response we have an array. The
    27 // first element in the array is the body string.  The second element in the
    28 // array is a boolean indicating whether that string should sniff as binary.
    29 var bodyList =
    30 [
    31  [ "Plaintext", false ]
    32 ];
    34 // List of possible BOMs
    35 var BOMList =
    36 [
    37  "\xFE\xFF",  // UTF-16BE
    38  "\xFF\xFE",  // UTF-16LE
    39  "\xEF\xBB\xBF", // UTF-8
    40  "\x00\x00\xFE\xFF", // UCS-4BE
    41  "\x00\x00\xFF\xFE" // UCS-4LE
    42 ];
    44 // Build up bodyList.  The things we treat as binary are ASCII codes 0-8,
    45 // 14-26, 28-31.  That is, the control char range, except for tab, newline,
    46 // vertical tab, form feed, carriage return, and ESC (this last being used by
    47 // Shift_JIS, apparently).
    48 function isBinaryChar(ch) {
    49   return (0 <= ch && ch <= 8) || (14 <= ch && ch <= 26) ||
    50          (28 <= ch && ch <= 31);
    51 }
    53 // Test chars on their own
    54 var i;
    55 for (i = 0; i <= 127; ++i) {  
    56   bodyList.push([ String.fromCharCode(i), isBinaryChar(i) ]);
    57 }
    59 // Test that having a BOM prevents plaintext sniffing
    60 var j;
    61 for (i = 0; i <= 127; ++i) {
    62   for (j = 0; j < BOMList.length; ++j) {
    63     bodyList.push([ BOMList[j] + String.fromCharCode(i, i), false ]);
    64   }
    65 }
    67 // Test that having a BOM requires at least 4 chars to kick in
    68 for (i = 0; i <= 127; ++i) {
    69   for (j = 0; j < BOMList.length; ++j) {
    70     bodyList.push([ BOMList[j] + String.fromCharCode(i),
    71                     BOMList[j].length == 2 && isBinaryChar(i) ]);
    72   }
    73 }
    75 function makeChan(headerIdx, bodyIdx) {
    76   var ios = Components.classes["@mozilla.org/network/io-service;1"]
    77                       .getService(Components.interfaces.nsIIOService);
    78   var chan =
    79     ios.newChannel("http://localhost:" + httpserv.identity.primaryPort +
    80                    "/" + headerIdx + "/" + bodyIdx, null, null)
    81        .QueryInterface(Components.interfaces.nsIHttpChannel);
    83   chan.loadFlags |=
    84     Components.interfaces.nsIChannel.LOAD_CALL_CONTENT_SNIFFERS;
    86   return chan;
    87 }
    89 function makeListener(headerIdx, bodyIdx) {
    90   var listener = {
    91     onStartRequest : function test_onStartR(request, ctx) {
    92       try {
    93         var chan = request.QueryInterface(Components.interfaces.nsIChannel);
    95         do_check_eq(chan.status, Components.results.NS_OK);
    97         var type = chan.contentType;
    99         var expectedType =
   100           contentTypeHeaderList[headerIdx][1] && bodyList[bodyIdx][1] ?
   101             "application/x-vnd.mozilla.guess-from-ext" : "text/plain";
   102         if (expectedType != type) {
   103           do_throw("Unexpected sniffed type '" + type + "'.  " +
   104                    "Should be '" + expectedType + "'.  " +
   105                    "Header is ['" +
   106                      contentTypeHeaderList[headerIdx][0] + "', " +
   107                      contentTypeHeaderList[headerIdx][1] + "].  " +
   108                    "Body is ['" +
   109                      bodyList[bodyIdx][0].toSource() + "', " +
   110                      bodyList[bodyIdx][1] +
   111                    "].");
   112         }
   113         do_check_eq(expectedType, type);
   114       } catch (e) {
   115         do_throw("Unexpected exception: " + e);
   116       }
   118       throw Components.results.NS_ERROR_ABORT;
   119     },
   121     onDataAvailable: function test_ODA() {
   122       do_throw("Should not get any data!");
   123     },
   125     onStopRequest: function test_onStopR(request, ctx, status) {
   126       // Advance to next test
   127       ++headerIdx;
   128       if (headerIdx == contentTypeHeaderList.length) {
   129         headerIdx = 0;
   130         ++bodyIdx;
   131       }
   133       if (bodyIdx == bodyList.length) {
   134         do_test_pending();
   135         httpserv.stop(do_test_finished);
   136       } else {
   137         doTest(headerIdx, bodyIdx);
   138       }
   140       do_test_finished();
   141     }    
   142   };
   144   return listener;
   145 }
   147 function doTest(headerIdx, bodyIdx) {
   148   var chan = makeChan(headerIdx, bodyIdx);
   150   var listener = makeListener(headerIdx, bodyIdx);
   152   chan.asyncOpen(listener, null);
   154   do_test_pending();    
   155 }
   157 function createResponse(headerIdx, bodyIdx, metadata, response) {
   158   response.setHeader("Content-Type", contentTypeHeaderList[headerIdx][0], false);
   159   response.bodyOutputStream.write(bodyList[bodyIdx][0],
   160                                   bodyList[bodyIdx][0].length);
   161 }
   163 function makeHandler(headerIdx, bodyIdx) {
   164   var f = 
   165     function handlerClosure(metadata, response) {
   166       return createResponse(headerIdx, bodyIdx, metadata, response);
   167     };
   168   return f;
   169 }
   171 var httpserv;
   172 function run_test() {
   173   // disable again for everything for now (causes sporatic oranges)
   174   return;
   176   // disable on Windows for now, because it seems to leak sockets and die.
   177   // Silly operating system!
   178   // This is a really nasty way to detect Windows.  I wish we could do better.
   179   if ("@mozilla.org/windows-registry-key;1" in Cc) {
   180     return;
   181   }
   183   httpserv = new HttpServer();
   185   for (i = 0; i < contentTypeHeaderList.length; ++i) {
   186     for (j = 0; j < bodyList.length; ++j) {
   187       httpserv.registerPathHandler("/" + i + "/" + j, makeHandler(i, j));
   188     }
   189   }
   191   httpserv.start(-1);
   193   doTest(0, 0);
   194 }

mercurial