const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; Cu.import('resource://gre/modules/CSPUtils.jsm'); var httpserv = null; const POLICY_FROM_URI = "allow 'self'; img-src *"; const POLICY_PORT = 9000; const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy"; const POLICY_URI_RELATIVE = "/policy"; const DOCUMENT_URI = "http://localhost:" + POLICY_PORT + "/document"; const CSP_DOC_BODY = "CSP doc content"; const SD = CSPRep.SRC_DIRECTIVES; // this will get populated by run_tests() var TESTS = []; // helper to make URIs function mkuri(foo) { return Cc["@mozilla.org/network/io-service;1"] .getService(Ci.nsIIOService) .newURI(foo, null, null); } // helper to use .equals on stuff function do_check_equivalent(foo, bar, stack) { if (!stack) stack = Components.stack.caller; var text = foo + ".equals(" + bar + ")"; if (foo.equals && foo.equals(bar)) { dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " + stack.lineNumber + "] " + text + "\n"); return; } do_throw(text, stack); } function listener(csp, cspr_static) { this.buffer = ""; this._csp = csp; this._cspr_static = cspr_static; } listener.prototype = { onStartRequest: function (request, ctx) { }, onDataAvailable: function (request, ctx, stream, offset, count) { var sInputStream = Cc["@mozilla.org/scriptableinputstream;1"] .createInstance(Ci.nsIScriptableInputStream); sInputStream.init(stream); this.buffer = this.buffer.concat(sInputStream.read(count)); }, onStopRequest: function (request, ctx, status) { // make sure that we have the full document content, guaranteeing that // the document channel has been resumed, before we do the comparisons if (this.buffer == CSP_DOC_BODY) { // need to re-grab cspr since it may have changed inside the document's // nsIContentSecurityPolicy instance. The problem is, this cspr_str is a // string and not a policy due to the way it's exposed from // nsIContentSecurityPolicy, so we have to re-parse it. let cspr_str = this._csp.getPolicy(0); let cspr = CSPRep.fromString(cspr_str, mkuri(DOCUMENT_URI)); // and in reparsing it, we lose the 'self' relationships, so need to also // reparse the static one (or find a way to resolve 'self' in the parsed // policy when doing comparisons). let cspr_static_str = this._cspr_static.toString(); let cspr_static_reparse = CSPRep.fromString(cspr_static_str, mkuri(DOCUMENT_URI)); // not null, and one policy .equals the other one do_check_neq(null, cspr); do_check_true(cspr.equals(cspr_static_reparse)); // final teardown if (TESTS.length == 0) { httpserv.stop(do_test_finished); } else { do_test_finished(); (TESTS.shift())(); } } } }; function run_test() { httpserv = new HttpServer(); httpserv.registerPathHandler("/document", csp_doc_response); httpserv.registerPathHandler("/policy", csp_policy_response); httpserv.start(POLICY_PORT); TESTS = [ test_CSPRep_fromPolicyURI, test_CSPRep_fromRelativePolicyURI ]; // when this triggers the "onStopRequest" callback, it'll // go to the next test. (TESTS.shift())(); } function makeChan(url) { var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel); return chan; } function csp_doc_response(metadata, response) { response.setStatusLine(metadata.httpVersion, 200, "OK"); response.setHeader("Content-Type", "text/html", false); response.bodyOutputStream.write(CSP_DOC_BODY, CSP_DOC_BODY.length); } function csp_policy_response(metadata, response) { response.setStatusLine(metadata.httpVersion, 200, "OK"); response.setHeader("Content-Type", "text/csp", false); response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length); } ///////////////////// TEST POLICY_URI ////////////////////// function test_CSPRep_fromPolicyURI() { do_test_pending(); let csp = Cc["@mozilla.org/contentsecuritypolicy;1"] .createInstance(Ci.nsIContentSecurityPolicy); // once the policy-uri is returned we will compare our static CSPRep with one // we generated from the content we got back from the network to make sure // they are equivalent let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI)); // simulates the request for the parent document var docChan = makeChan(DOCUMENT_URI); docChan.asyncOpen(new listener(csp, cspr_static), null); // the resulting policy here can be discarded, since it's going to be // "allow *"; when the policy-uri fetching call-back happens, the *real* // policy will be in csp.policy CSPRep.fromString("policy-uri " + POLICY_URI, mkuri(DOCUMENT_URI), false, docChan, csp); } function test_CSPRep_fromRelativePolicyURI() { do_test_pending(); let csp = Cc["@mozilla.org/contentsecuritypolicy;1"] .createInstance(Ci.nsIContentSecurityPolicy); // once the policy-uri is returned we will compare our static CSPRep with one // we generated from the content we got back from the network to make sure // they are equivalent let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI)); // simulates the request for the parent document var docChan = makeChan(DOCUMENT_URI); docChan.asyncOpen(new listener(csp, cspr_static), null); // the resulting policy here can be discarded, since it's going to be // "allow *"; when the policy-uri fetching call-back happens, the *real* // policy will be in csp.policy CSPRep.fromString("policy-uri " + POLICY_URI_RELATIVE, mkuri(DOCUMENT_URI), false, docChan, csp); }