Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
1 var DEBUG = true;
3 var clientID = "HTTP";
4 var nsICache = Components.interfaces.nsICache;
6 function getEventQueue()
7 {
8 var nsIEventQueueService = Components.interfaces.nsIEventQueueService;
9 var CID = Components.classes["@mozilla.org/event-queue-service;1"];
10 var service = CID.getService(nsIEventQueueService);
11 return service.getSpecialEventQueue(nsIEventQueueService.CURRENT_THREAD_EVENT_QUEUE);
12 }
14 var eventQueue = getEventQueue();
16 function getCacheService()
17 {
18 var nsCacheService = Components.classes["@mozilla.org/network/cache-service;1"];
19 var service = nsCacheService.getService(Components.interfaces.nsICacheService);
20 return service;
21 }
23 function createCacheSession(clientID, storagePolicy, streamable)
24 {
25 var service = getCacheService();
26 var session = service.createSession(clientID, storagePolicy, streamable);
27 return session;
28 }
30 function openCacheEntry(url, mode)
31 {
32 var session = createCacheSession(clientID, nsICache.STORE_ON_DISK, true);
33 var entry = session.openCacheEntry(url, mode);
34 return entry;
35 }
37 function wrapInputStream(input)
38 {
39 var nsIScriptableInputStream = Components.interfaces.nsIScriptableInputStream;
40 var factory = Components.classes["@mozilla.org/scriptableinputstream;1"];
41 var wrapper = factory.createInstance(nsIScriptableInputStream);
42 wrapper.init(input);
43 return wrapper;
44 }
46 function download(key)
47 {
48 var url = new java.net.URL(key);
49 var data = "";
50 var buffer = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 65536);
51 var stream = url.openStream();
52 while (true) {
53 var count = stream.read(buffer);
54 if (count <= 0)
55 break;
56 var str = new java.lang.String(buffer, 0, count);
57 data += str;
58 }
59 stream.close();
60 return data;
61 }
63 function write(url, data)
64 {
65 var key = url.toString();
66 var outputEntry = openCacheEntry(key, nsICache.ACCESS_WRITE);
67 var output = outputEntry.transport.openOutputStream(0, -1, 0);
68 var count = output.write(data, data.length);
70 // store some metadata.
71 outputEntry.setMetaDataElement("size", data.length);
73 output.close();
74 outputEntry.markValid();
75 outputEntry.close();
77 return count;
78 }
80 function CacheListener()
81 {
82 this.done = false;
83 }
85 CacheListener.prototype = {
86 QueryInterface : function(iid)
87 {
88 if (iid.equals(Components.interfaces.nsICacheListener))
89 return this;
90 throw Components.results.NS_NOINTERFACE;
91 },
93 onCacheEntryAvailable : function(/* in nsICacheEntryDescriptor */ descriptor,
94 /* in nsCacheAccessMode */ accessGranted,
95 /* in nsresult */ status)
96 {
97 this.descriptor = descriptor;
98 this.status = status;
99 this.done = true;
100 }
101 };
103 function asyncOpenCacheEntry(url, mode)
104 {
105 var session = createCacheSession(clientID, nsICache.STORE_ON_DISK, true);
106 var listener = new CacheListener();
107 session.asyncOpenCacheEntry(url, mode, listener);
108 while (!listener.done)
109 eventQueue.processPendingEvents();
110 return listener.descriptor;
111 }
113 function asyncWrite(key, data)
114 {
115 var outputEntry = asyncOpenCacheEntry(key, nsICache.ACCESS_WRITE);
117 var output = outputEntry.transport.openOutputStream(0, -1, 0);
118 var count = output.write(data, data.length);
120 // store some metadata.
121 outputEntry.setMetaDataElement("size", data.length);
123 output.close();
124 outputEntry.markValid();
125 outputEntry.close();
127 return count;
128 }
130 function StreamListener()
131 {
132 this.done = false;
133 this.data = "";
134 this.wrapper = null;
135 }
137 StreamListener.prototype = {
138 QueryInterface : function(iid)
139 {
140 if (iid.equals(Components.interfaces.nsIStreamListener) ||
141 iid.equals(Components.interfaces.nsIStreamObserver))
142 return this;
143 throw Components.results.NS_NOINTERFACE;
144 },
146 onStartRequest : function(request, context)
147 {
148 },
150 onStopRequest : function(request, context, statusCode, statusText)
151 {
152 this.statusCode = statusCode;
153 this.done = true;
154 },
156 onDataAvailable : function(request, context, input, offset, count)
157 {
158 if (this.wrapper == null)
159 this.wrapper = wrapInputStream(input);
160 input = this.wrapper;
161 this.data += input.read(count);
162 }
163 };
165 function asyncRead(key)
166 {
167 var inputEntry = asyncOpenCacheEntry(key, nsICache.ACCESS_READ);
168 var listener = new StreamListener();
169 inputEntry.transport.asyncRead(listener, null, 0, inputEntry.dataSize, 0);
170 while (!listener.done)
171 eventQueue.processPendingEvents();
172 inputEntry.close();
173 return listener.data;
174 }
176 function read(key)
177 {
178 var inputEntry = openCacheEntry(key, nsICache.ACCESS_READ);
179 var input = wrapInputStream(inputEntry.transport.openInputStream(0, -1, 0));
180 var data = input.read(input.available());
181 input.close();
182 inputEntry.close();
183 return data;
184 }
186 function readMetaData(key, element)
187 {
188 var inputEntry = openCacheEntry(key, nsICache.ACCESS_READ);
189 var metadata = inputEntry.getMetaDataElement(element);
190 inputEntry.close();
191 return metadata;
192 }
194 function doom(url)
195 {
196 var key = url.toString();
197 var doomedEntry = openCacheEntry(key, nsICache.ACCESS_READ_WRITE);
198 doomedEntry.doom();
199 doomedEntry.close();
200 }
202 // two keys which are known to collide right now.
203 var key1 = "http://a772.g.akamai.net/7/772/51/7648437e551b56/www.apple.com/t/2001/us/en/i/2.gif";
204 var key2 = "http://a772.g.akamai.net/7/772/51/70601300d0bde6/www.apple.com/t/2001/us/en/i/1right.gif";
206 function test()
207 {
208 // 1. generate a collision, and close the colliding entry first.
209 var entry1 = asyncOpenCacheEntry(key1, nsICache.ACCESS_READ_WRITE);
210 var data1 = key1;
211 entry1.setMetaDataElement("size", data1.length);
212 entry1.markValid();
213 var output1 = entry1.transport.openOutputStream(0, -1, 0);
214 output1.write(data1, data1.length);
216 var entry2 = asyncOpenCacheEntry(key2, nsICache.ACCESS_READ_WRITE);
217 var data2 = key2;
218 entry2.setMetaDataElement("size", data2.length);
219 entry2.markValid();
220 var output2 = entry2.transport.openOutputStream(0, -1, 0);
221 output2.write(data2, data2.length);
223 output1.close();
224 output2.close();
226 entry1.close();
227 entry2.close();
228 }
230 function median(array)
231 {
232 var cmp = function(x, y) { return x - y; }
233 array.sort(cmp);
234 var middle = Math.floor(array.length / 2);
235 return array[middle];
236 }
238 function sum(array)
239 {
240 var s = 0;
241 var len = array.length;
242 for (var i = 0; i < len; ++i)
243 s += array[i];
244 return s;
245 }
247 function time()
248 {
249 var N = 50;
250 var System = java.lang.System;
251 var url = new java.net.URL("http://www.mozilla.org");
252 var key = url.toString();
253 var downloadTimes = new Array();
254 for (var i = 0; i < N; ++i) {
255 var begin = System.currentTimeMillis();
256 download(url);
257 var end = System.currentTimeMillis();
258 downloadTimes.push(end - begin);
259 }
260 var downloadTotal = sum(downloadTimes);
261 var downloadMean = downloadTotal / N;
262 var downloadMedian = median(downloadTimes);
263 print("" + N + " downloads took " + downloadTotal + " milliseconds.");
264 print("mean = " + downloadMean + " milliseconds.");
265 print("median = " + downloadMedian + " milliseconds.");
267 var readTimes = new Array();
268 for (var i = 0; i < N; ++i) {
269 var begin = System.currentTimeMillis();
270 asyncRead(key);
271 var end = System.currentTimeMillis();
272 readTimes.push(end - begin);
273 }
274 var readTotal = sum(readTimes);
275 var readMean = readTotal / N;
276 var readMedian = median(readTimes);
277 print("" + N + " reads took " + readTotal + " milliseconds.");
278 print("mean = " + readMean + " milliseconds.");
279 print("median = " + readMedian + " milliseconds.");
280 }
282 // load the cache service before doing anything with Java...
283 getCacheService();
285 if (DEBUG) {
286 print("cache service loaded.");
287 } else {
288 print("running disk cache test.");
289 test();
290 print("disk cache test complete.");
291 }