|
1 |
|
2 const Cc = Components.classes; |
|
3 const Ci = Components.interfaces; |
|
4 const Cu = Components.utils; |
|
5 const Cr = Components.results; |
|
6 |
|
7 Cu.import('resource://gre/modules/CSPUtils.jsm'); |
|
8 |
|
9 var httpserv = null; |
|
10 |
|
11 const POLICY_FROM_URI = "allow 'self'; img-src *"; |
|
12 const POLICY_PORT = 9000; |
|
13 const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy"; |
|
14 const POLICY_URI_RELATIVE = "/policy"; |
|
15 const DOCUMENT_URI = "http://localhost:" + POLICY_PORT + "/document"; |
|
16 const CSP_DOC_BODY = "CSP doc content"; |
|
17 const SD = CSPRep.SRC_DIRECTIVES; |
|
18 |
|
19 // this will get populated by run_tests() |
|
20 var TESTS = []; |
|
21 |
|
22 // helper to make URIs |
|
23 function mkuri(foo) { |
|
24 return Cc["@mozilla.org/network/io-service;1"] |
|
25 .getService(Ci.nsIIOService) |
|
26 .newURI(foo, null, null); |
|
27 } |
|
28 |
|
29 // helper to use .equals on stuff |
|
30 function do_check_equivalent(foo, bar, stack) { |
|
31 if (!stack) |
|
32 stack = Components.stack.caller; |
|
33 |
|
34 var text = foo + ".equals(" + bar + ")"; |
|
35 |
|
36 if (foo.equals && foo.equals(bar)) { |
|
37 dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " + |
|
38 stack.lineNumber + "] " + text + "\n"); |
|
39 return; |
|
40 } |
|
41 do_throw(text, stack); |
|
42 } |
|
43 |
|
44 function listener(csp, cspr_static) { |
|
45 this.buffer = ""; |
|
46 this._csp = csp; |
|
47 this._cspr_static = cspr_static; |
|
48 } |
|
49 |
|
50 listener.prototype = { |
|
51 onStartRequest: function (request, ctx) { |
|
52 }, |
|
53 |
|
54 onDataAvailable: function (request, ctx, stream, offset, count) { |
|
55 var sInputStream = Cc["@mozilla.org/scriptableinputstream;1"] |
|
56 .createInstance(Ci.nsIScriptableInputStream); |
|
57 sInputStream.init(stream); |
|
58 this.buffer = this.buffer.concat(sInputStream.read(count)); |
|
59 }, |
|
60 |
|
61 onStopRequest: function (request, ctx, status) { |
|
62 // make sure that we have the full document content, guaranteeing that |
|
63 // the document channel has been resumed, before we do the comparisons |
|
64 if (this.buffer == CSP_DOC_BODY) { |
|
65 |
|
66 // need to re-grab cspr since it may have changed inside the document's |
|
67 // nsIContentSecurityPolicy instance. The problem is, this cspr_str is a |
|
68 // string and not a policy due to the way it's exposed from |
|
69 // nsIContentSecurityPolicy, so we have to re-parse it. |
|
70 let cspr_str = this._csp.getPolicy(0); |
|
71 let cspr = CSPRep.fromString(cspr_str, mkuri(DOCUMENT_URI)); |
|
72 |
|
73 // and in reparsing it, we lose the 'self' relationships, so need to also |
|
74 // reparse the static one (or find a way to resolve 'self' in the parsed |
|
75 // policy when doing comparisons). |
|
76 let cspr_static_str = this._cspr_static.toString(); |
|
77 let cspr_static_reparse = CSPRep.fromString(cspr_static_str, mkuri(DOCUMENT_URI)); |
|
78 |
|
79 // not null, and one policy .equals the other one |
|
80 do_check_neq(null, cspr); |
|
81 do_check_true(cspr.equals(cspr_static_reparse)); |
|
82 |
|
83 // final teardown |
|
84 if (TESTS.length == 0) { |
|
85 httpserv.stop(do_test_finished); |
|
86 } else { |
|
87 do_test_finished(); |
|
88 (TESTS.shift())(); |
|
89 } |
|
90 } |
|
91 } |
|
92 }; |
|
93 |
|
94 function run_test() { |
|
95 httpserv = new HttpServer(); |
|
96 httpserv.registerPathHandler("/document", csp_doc_response); |
|
97 httpserv.registerPathHandler("/policy", csp_policy_response); |
|
98 httpserv.start(POLICY_PORT); |
|
99 TESTS = [ test_CSPRep_fromPolicyURI, test_CSPRep_fromRelativePolicyURI ]; |
|
100 |
|
101 // when this triggers the "onStopRequest" callback, it'll |
|
102 // go to the next test. |
|
103 (TESTS.shift())(); |
|
104 } |
|
105 |
|
106 function makeChan(url) { |
|
107 var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); |
|
108 var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel); |
|
109 return chan; |
|
110 } |
|
111 |
|
112 function csp_doc_response(metadata, response) { |
|
113 response.setStatusLine(metadata.httpVersion, 200, "OK"); |
|
114 response.setHeader("Content-Type", "text/html", false); |
|
115 response.bodyOutputStream.write(CSP_DOC_BODY, CSP_DOC_BODY.length); |
|
116 } |
|
117 |
|
118 function csp_policy_response(metadata, response) { |
|
119 response.setStatusLine(metadata.httpVersion, 200, "OK"); |
|
120 response.setHeader("Content-Type", "text/csp", false); |
|
121 response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length); |
|
122 } |
|
123 |
|
124 ///////////////////// TEST POLICY_URI ////////////////////// |
|
125 function test_CSPRep_fromPolicyURI() { |
|
126 do_test_pending(); |
|
127 let csp = Cc["@mozilla.org/contentsecuritypolicy;1"] |
|
128 .createInstance(Ci.nsIContentSecurityPolicy); |
|
129 // once the policy-uri is returned we will compare our static CSPRep with one |
|
130 // we generated from the content we got back from the network to make sure |
|
131 // they are equivalent |
|
132 let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI)); |
|
133 |
|
134 // simulates the request for the parent document |
|
135 var docChan = makeChan(DOCUMENT_URI); |
|
136 docChan.asyncOpen(new listener(csp, cspr_static), null); |
|
137 |
|
138 // the resulting policy here can be discarded, since it's going to be |
|
139 // "allow *"; when the policy-uri fetching call-back happens, the *real* |
|
140 // policy will be in csp.policy |
|
141 CSPRep.fromString("policy-uri " + POLICY_URI, |
|
142 mkuri(DOCUMENT_URI), false, docChan, csp); |
|
143 } |
|
144 |
|
145 function test_CSPRep_fromRelativePolicyURI() { |
|
146 do_test_pending(); |
|
147 let csp = Cc["@mozilla.org/contentsecuritypolicy;1"] |
|
148 .createInstance(Ci.nsIContentSecurityPolicy); |
|
149 // once the policy-uri is returned we will compare our static CSPRep with one |
|
150 // we generated from the content we got back from the network to make sure |
|
151 // they are equivalent |
|
152 let cspr_static = CSPRep.fromString(POLICY_FROM_URI, mkuri(DOCUMENT_URI)); |
|
153 |
|
154 // simulates the request for the parent document |
|
155 var docChan = makeChan(DOCUMENT_URI); |
|
156 docChan.asyncOpen(new listener(csp, cspr_static), null); |
|
157 |
|
158 // the resulting policy here can be discarded, since it's going to be |
|
159 // "allow *"; when the policy-uri fetching call-back happens, the *real* |
|
160 // policy will be in csp.policy |
|
161 CSPRep.fromString("policy-uri " + POLICY_URI_RELATIVE, |
|
162 mkuri(DOCUMENT_URI), false, docChan, csp); |
|
163 } |