tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_file_protocol.js (7358B)


      1 /* run some tests on the file:// protocol handler */
      2 
      3 "use strict";
      4 
      5 const PR_RDONLY = 0x1; // see prio.h
      6 
      7 const special_type = "application/x-our-special-type";
      8 
      9 [
     10  test_read_file,
     11  test_read_dir_1,
     12  test_read_dir_2,
     13  test_upload_file,
     14  test_load_shelllink,
     15  do_test_finished,
     16 ].forEach(f => add_test(f));
     17 
     18 function new_file_input_stream(file, buffered) {
     19  var stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
     20    Ci.nsIFileInputStream
     21  );
     22  stream.init(file, PR_RDONLY, 0, 0);
     23  if (!buffered) {
     24    return stream;
     25  }
     26 
     27  var buffer = Cc[
     28    "@mozilla.org/network/buffered-input-stream;1"
     29  ].createInstance(Ci.nsIBufferedInputStream);
     30  buffer.init(stream, 4096);
     31  return buffer;
     32 }
     33 
     34 function new_file_channel(file) {
     35  let uri = Services.io.newFileURI(file);
     36  return NetUtil.newChannel({
     37    uri,
     38    loadingPrincipal: Services.scriptSecurityManager.createContentPrincipal(
     39      uri,
     40      {}
     41    ),
     42    securityFlags: Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT,
     43    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     44  });
     45 }
     46 
     47 /*
     48 * stream listener
     49 * this listener has some additional file-specific tests, so we can't just use
     50 * ChannelListener here.
     51 */
     52 function FileStreamListener(closure) {
     53  this._closure = closure;
     54 }
     55 FileStreamListener.prototype = {
     56  _closure: null,
     57  _buffer: "",
     58  _got_onstartrequest: false,
     59  _got_onstoprequest: false,
     60  _contentLen: -1,
     61 
     62  _isDir(request) {
     63    request.QueryInterface(Ci.nsIFileChannel);
     64    return request.file.isDirectory();
     65  },
     66 
     67  QueryInterface: ChromeUtils.generateQI([
     68    "nsIStreamListener",
     69    "nsIRequestObserver",
     70  ]),
     71 
     72  onStartRequest(request) {
     73    if (this._got_onstartrequest) {
     74      do_throw("Got second onStartRequest event!");
     75    }
     76    this._got_onstartrequest = true;
     77 
     78    if (!this._isDir(request)) {
     79      request.QueryInterface(Ci.nsIChannel);
     80      this._contentLen = request.contentLength;
     81      if (this._contentLen == -1) {
     82        do_throw("Content length is unknown in onStartRequest!");
     83      }
     84    }
     85  },
     86 
     87  onDataAvailable(request, stream, offset, count) {
     88    if (!this._got_onstartrequest) {
     89      do_throw("onDataAvailable without onStartRequest event!");
     90    }
     91    if (this._got_onstoprequest) {
     92      do_throw("onDataAvailable after onStopRequest event!");
     93    }
     94    if (!request.isPending()) {
     95      do_throw("request reports itself as not pending from onStartRequest!");
     96    }
     97 
     98    this._buffer = this._buffer.concat(read_stream(stream, count));
     99  },
    100 
    101  onStopRequest(request, status) {
    102    if (!this._got_onstartrequest) {
    103      do_throw("onStopRequest without onStartRequest event!");
    104    }
    105    if (this._got_onstoprequest) {
    106      do_throw("Got second onStopRequest event!");
    107    }
    108    this._got_onstoprequest = true;
    109    if (!Components.isSuccessCode(status)) {
    110      do_throw("Failed to load file: " + status.toString(16));
    111    }
    112    if (status != request.status) {
    113      do_throw("request.status does not match status arg to onStopRequest!");
    114    }
    115    if (request.isPending()) {
    116      do_throw("request reports itself as pending from onStopRequest!");
    117    }
    118    if (this._contentLen != -1 && this._buffer.length != this._contentLen) {
    119      do_throw("did not read nsIChannel.contentLength number of bytes!");
    120    }
    121 
    122    this._closure(this._buffer);
    123  },
    124 };
    125 
    126 function test_read_file() {
    127  dump("*** test_read_file\n");
    128 
    129  var file = do_get_file("../unit/data/test_readline6.txt");
    130  var chan = new_file_channel(file);
    131 
    132  function on_read_complete(data) {
    133    dump("*** test_read_file.on_read_complete\n");
    134 
    135    // bug 326693
    136    if (chan.contentType != special_type) {
    137      do_throw(
    138        "Type mismatch! Is <" +
    139          chan.contentType +
    140          ">, should be <" +
    141          special_type +
    142          ">"
    143      );
    144    }
    145 
    146    /* read completed successfully.  now read data directly from file,
    147       and compare the result. */
    148    var stream = new_file_input_stream(file, false);
    149    var result = read_stream(stream, stream.available());
    150    if (result != data) {
    151      do_throw("Stream contents do not match with direct read!");
    152    }
    153    run_next_test();
    154  }
    155 
    156  chan.contentType = special_type;
    157  chan.asyncOpen(new FileStreamListener(on_read_complete));
    158 }
    159 
    160 function do_test_read_dir(set_type, expected_type) {
    161  dump("*** test_read_dir(" + set_type + ", " + expected_type + ")\n");
    162 
    163  var file = do_get_tempdir();
    164  var chan = new_file_channel(file);
    165 
    166  function on_read_complete() {
    167    dump(
    168      "*** test_read_dir.on_read_complete(" +
    169        set_type +
    170        ", " +
    171        expected_type +
    172        ")\n"
    173    );
    174 
    175    // bug 326693
    176    if (chan.contentType != expected_type) {
    177      do_throw(
    178        "Type mismatch! Is <" +
    179          chan.contentType +
    180          ">, should be <" +
    181          expected_type +
    182          ">"
    183      );
    184    }
    185 
    186    run_next_test();
    187  }
    188 
    189  if (set_type) {
    190    chan.contentType = expected_type;
    191  }
    192  chan.asyncOpen(new FileStreamListener(on_read_complete));
    193 }
    194 
    195 function test_read_dir_1() {
    196  return do_test_read_dir(false, "application/http-index-format");
    197 }
    198 
    199 function test_read_dir_2() {
    200  return do_test_read_dir(true, special_type);
    201 }
    202 
    203 function test_upload_file() {
    204  dump("*** test_upload_file\n");
    205 
    206  var file = do_get_file("../unit/data/test_readline6.txt"); // file to upload
    207  var dest = do_get_tempdir(); // file upload destination
    208  dest.append("junk.dat");
    209  dest.createUnique(dest.NORMAL_FILE_TYPE, 0o600);
    210 
    211  var uploadstream = new_file_input_stream(file, true);
    212 
    213  var chan = new_file_channel(dest);
    214  chan.QueryInterface(Ci.nsIUploadChannel);
    215  chan.setUploadStream(uploadstream, "", file.fileSize);
    216 
    217  function on_upload_complete(data) {
    218    dump("*** test_upload_file.on_upload_complete\n");
    219 
    220    // bug 326693
    221    if (chan.contentType != special_type) {
    222      do_throw(
    223        "Type mismatch! Is <" +
    224          chan.contentType +
    225          ">, should be <" +
    226          special_type +
    227          ">"
    228      );
    229    }
    230 
    231    /* upload of file completed successfully. */
    232    if (data.length) {
    233      do_throw("Upload resulted in data!");
    234    }
    235 
    236    var oldstream = new_file_input_stream(file, false);
    237    var newstream = new_file_input_stream(dest, false);
    238    var olddata = read_stream(oldstream, oldstream.available());
    239    var newdata = read_stream(newstream, newstream.available());
    240    if (olddata != newdata) {
    241      do_throw("Stream contents do not match after file copy!");
    242    }
    243    oldstream.close();
    244    newstream.close();
    245 
    246    /* cleanup... also ensures that the destination file is not in
    247       use when OnStopRequest is called. */
    248    try {
    249      dest.remove(false);
    250    } catch (e) {
    251      dump(e + "\n");
    252      do_throw("Unable to remove uploaded file!\n");
    253    }
    254 
    255    run_next_test();
    256  }
    257 
    258  chan.contentType = special_type;
    259  chan.asyncOpen(new FileStreamListener(on_upload_complete));
    260 }
    261 
    262 function test_load_shelllink() {
    263  // lnk files should not resolve to their targets
    264  dump("*** test_load_shelllink\n");
    265  let file = do_get_file("data/system_root.lnk", false);
    266  var chan = new_file_channel(file);
    267 
    268  // The original URI path should be the same as the URI path
    269  Assert.equal(chan.URI.pathQueryRef, chan.originalURI.pathQueryRef);
    270 
    271  // The original URI path should be the same as the lnk file path
    272  Assert.equal(
    273    chan.originalURI.pathQueryRef,
    274    Services.io.newFileURI(file).pathQueryRef
    275  );
    276  run_next_test();
    277 }