// This testcase verifies that channels can't be reopened
// See https://bugzilla.mozilla.org/show_bug.cgi?id=372486

"use strict";

ChromeUtils.import("resource://testing-common/httpd.js");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");

const BinaryInputStream = Components.Constructor(
  "@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream",
  "setInputStream");

const NS_ERROR_IN_PROGRESS = 0x804b000f;
const NS_ERROR_ALREADY_OPENED = 0x804b0049;

var chan = null;
var httpserv = null;

[
  test_data_channel,
  test_http_channel,
  test_file_channel,
  // Commented by default as it relies on external ressources
  //test_ftp_channel,
  end
].forEach(f => add_test(f));

// Utility functions

function makeChan(url) {
  return chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true})
                       .QueryInterface(Ci.nsIChannel);
}

function new_file_channel(file) {
  var ios = Cc["@mozilla.org/network/io-service;1"]
              .getService(Ci.nsIIOService);
  return NetUtil.newChannel({
    uri: ios.newFileURI(file),
    loadUsingSystemPrincipal: true
  });
}


function check_throws(closure, error) {
  var thrown = false;
  try {
    closure();
  } catch (e) {
    if (error instanceof Array) {
      Assert.notEqual(error.indexOf(e.result), -1);
    } else {
      Assert.equal(e.result, error);
    }
    thrown = true;
  }
  Assert.ok(thrown);
}

function check_open_throws(error) {
  check_throws(function() {
    chan.open2(listener);
  }, error);
}

function check_async_open_throws(error) {
  check_throws(function() {
    chan.asyncOpen2(listener);
  }, error);
}

var listener = {
  onStartRequest: function test_onStartR(request, ctx) {
    check_async_open_throws(NS_ERROR_IN_PROGRESS);
  },

  onDataAvailable: function test_ODA(request, cx, inputStream,
                                     offset, count) {
    new BinaryInputStream(inputStream).readByteArray(count); // required by API
    check_async_open_throws(NS_ERROR_IN_PROGRESS);
  },

  onStopRequest: function test_onStopR(request, ctx, status) {
    // Once onStopRequest is reached, the channel is marked as having been
    // opened
    check_async_open_throws(NS_ERROR_ALREADY_OPENED);
    do_timeout(0, after_channel_closed);
  }
};

function after_channel_closed() {
  check_async_open_throws(NS_ERROR_ALREADY_OPENED);

  run_next_test();
}

function test_channel(createChanClosure) {
  // First, synchronous reopening test
  chan = createChanClosure();
  var inputStream = chan.open2();
  check_open_throws(NS_ERROR_IN_PROGRESS);
  check_async_open_throws([NS_ERROR_IN_PROGRESS, NS_ERROR_ALREADY_OPENED]);
  
  // Then, asynchronous one
  chan = createChanClosure();
  chan.asyncOpen2(listener);
  check_open_throws(NS_ERROR_IN_PROGRESS);
  check_async_open_throws(NS_ERROR_IN_PROGRESS);
}

function test_data_channel() {
  test_channel(function() {
    return makeChan("data:text/plain,foo");
  });
}

function test_http_channel() {
  test_channel(function() {
    return makeChan("http://localhost:" + httpserv.identity.primaryPort + "/");
  });
}

function test_file_channel() {
  var file = do_get_file("data/test_readline1.txt");
  test_channel(function() {
    return new_file_channel(file);
  });
}

// Uncomment test_ftp_channel in test_array to test this
function test_ftp_channel() {
  test_channel(function() {
    return makeChan("ftp://ftp.mozilla.org/pub/mozilla.org/README");
  });
}

function end() {
  httpserv.stop(do_test_finished);
}

function run_test() {
  // start server
  httpserv = new HttpServer();
  httpserv.start(-1);

  run_next_test();
}
