|
1 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
2 |
|
3 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", |
|
4 "resource://gre/modules/NetUtil.jsm"); |
|
5 XPCOMUtils.defineLazyModuleGetter(this, "Promise", |
|
6 "resource://gre/modules/Promise.jsm"); |
|
7 // Global test server for serving safebrowsing updates. |
|
8 let gHttpServ = null; |
|
9 // Global nsIUrlClassifierDBService |
|
10 let gDbService = Cc["@mozilla.org/url-classifier/dbservice;1"] |
|
11 .getService(Ci.nsIUrlClassifierDBService); |
|
12 // Security manager for creating nsIPrincipals from URIs |
|
13 let gSecMan = Cc["@mozilla.org/scriptsecuritymanager;1"] |
|
14 .getService(Ci.nsIScriptSecurityManager); |
|
15 |
|
16 // A map of tables to arrays of update redirect urls. |
|
17 let gTables = {}; |
|
18 |
|
19 // Construct an update from a file. |
|
20 function readFileToString(aFilename) { |
|
21 let f = do_get_file(aFilename); |
|
22 let stream = Cc["@mozilla.org/network/file-input-stream;1"] |
|
23 .createInstance(Ci.nsIFileInputStream); |
|
24 stream.init(f, -1, 0, 0); |
|
25 let buf = NetUtil.readInputStreamToString(stream, stream.available()); |
|
26 return buf; |
|
27 } |
|
28 |
|
29 // Registers a table for which to serve update chunks. Returns a promise that |
|
30 // resolves when that chunk has been downloaded. |
|
31 function registerTableUpdate(aTable, aFilename) { |
|
32 let deferred = Promise.defer(); |
|
33 // If we haven't been given an update for this table yet, add it to the map |
|
34 if (!(aTable in gTables)) { |
|
35 gTables[aTable] = []; |
|
36 } |
|
37 |
|
38 // The number of chunks associated with this table. |
|
39 let numChunks = gTables[aTable].length + 1; |
|
40 let redirectPath = "/" + aTable + "-" + numChunks; |
|
41 let redirectUrl = "localhost:4444" + redirectPath; |
|
42 |
|
43 // Store redirect url for that table so we can return it later when we |
|
44 // process an update request. |
|
45 gTables[aTable].push(redirectUrl); |
|
46 |
|
47 gHttpServ.registerPathHandler(redirectPath, function(request, response) { |
|
48 do_print("Mock safebrowsing server handling request for " + redirectPath); |
|
49 let contents = readFileToString(aFilename); |
|
50 response.setHeader("Content-Type", |
|
51 "application/vnd.google.safebrowsing-update", false); |
|
52 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
53 response.bodyOutputStream.write(contents, contents.length); |
|
54 deferred.resolve(contents); |
|
55 }); |
|
56 return deferred.promise; |
|
57 } |
|
58 |
|
59 // Construct a response with redirect urls. |
|
60 function processUpdateRequest() { |
|
61 let response = "n:1000\n"; |
|
62 for (let table in gTables) { |
|
63 response += "i:" + table + "\n"; |
|
64 for (let i = 0; i < gTables[table].length; ++i) { |
|
65 response += "u:" + gTables[table][i] + "\n"; |
|
66 } |
|
67 } |
|
68 do_print("Returning update response: " + response); |
|
69 return response; |
|
70 } |
|
71 |
|
72 // Set up our test server to handle update requests. |
|
73 function run_test() { |
|
74 gHttpServ = new HttpServer(); |
|
75 gHttpServ.registerDirectory("/", do_get_cwd()); |
|
76 |
|
77 gHttpServ.registerPathHandler("/downloads", function(request, response) { |
|
78 let buf = NetUtil.readInputStreamToString(request.bodyInputStream, |
|
79 request.bodyInputStream.available()); |
|
80 let blob = processUpdateRequest(); |
|
81 response.setHeader("Content-Type", |
|
82 "application/vnd.google.safebrowsing-update", false); |
|
83 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
84 response.bodyOutputStream.write(blob, blob.length); |
|
85 }); |
|
86 |
|
87 gHttpServ.start(4444); |
|
88 run_next_test(); |
|
89 } |
|
90 |
|
91 function createURI(s) { |
|
92 let service = Cc["@mozilla.org/network/io-service;1"] |
|
93 .getService(Ci.nsIIOService); |
|
94 return service.newURI(s, null, null); |
|
95 } |
|
96 |
|
97 // Just throw if we ever get an update or download error. |
|
98 function handleError(aEvent) { |
|
99 do_throw("We didn't download or update correctly: " + aEvent); |
|
100 } |
|
101 |
|
102 add_test(function test_update() { |
|
103 let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"] |
|
104 .getService(Ci.nsIUrlClassifierStreamUpdater); |
|
105 streamUpdater.updateUrl = "http://localhost:4444/downloads"; |
|
106 |
|
107 // Load up some update chunks for the safebrowsing server to serve. |
|
108 registerTableUpdate("goog-downloadwhite-digest256", "data/digest1.chunk"); |
|
109 registerTableUpdate("goog-downloadwhite-digest256", "data/digest2.chunk"); |
|
110 |
|
111 // Download some updates, and don't continue until the downloads are done. |
|
112 function updateSuccess(aEvent) { |
|
113 // Timeout of n:1000 is constructed in processUpdateRequest above and |
|
114 // passed back in the callback in nsIUrlClassifierStreamUpdater on success. |
|
115 do_check_eq("1000", aEvent); |
|
116 do_print("All data processed"); |
|
117 run_next_test(); |
|
118 } |
|
119 streamUpdater.downloadUpdates( |
|
120 "goog-downloadwhite-digest256", |
|
121 "goog-downloadwhite-digest256;\n", |
|
122 updateSuccess, handleError, handleError); |
|
123 }); |
|
124 |
|
125 add_test(function test_url_not_whitelisted() { |
|
126 let uri = createURI("http://example.com"); |
|
127 let principal = gSecMan.getNoAppCodebasePrincipal(uri); |
|
128 gDbService.lookup(principal, "goog-downloadwhite-digest256", |
|
129 function handleEvent(aEvent) { |
|
130 // This URI is not on any lists. |
|
131 do_check_eq("", aEvent); |
|
132 run_next_test(); |
|
133 }); |
|
134 }); |
|
135 |
|
136 add_test(function test_url_whitelisted() { |
|
137 // Hash of "whitelisted.com/" (canonicalized URL) is: |
|
138 // 93CA5F48E15E9861CD37C2D95DB43D23CC6E6DE5C3F8FA6E8BE66F97CC518907 |
|
139 let uri = createURI("http://whitelisted.com"); |
|
140 let principal = gSecMan.getNoAppCodebasePrincipal(uri); |
|
141 gDbService.lookup(principal, "goog-downloadwhite-digest256", |
|
142 function handleEvent(aEvent) { |
|
143 do_check_eq("goog-downloadwhite-digest256", aEvent); |
|
144 run_next_test(); |
|
145 }); |
|
146 }); |