Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /**
2 * Test TCPSocket.js by creating an XPCOM-style server socket, then sending
3 * data in both directions and making sure each side receives their data
4 * correctly and with the proper events.
5 *
6 * This test is derived from netwerk/test/unit/test_socks.js, except we don't
7 * involve a subprocess.
8 *
9 * Future work:
10 * - SSL. see https://bugzilla.mozilla.org/show_bug.cgi?id=466524
11 * https://bugzilla.mozilla.org/show_bug.cgi?id=662180
12 * Alternatively, mochitests could be used.
13 * - Testing overflow logic.
14 *
15 **/
17 const Cc = Components.classes;
18 const Ci = Components.interfaces;
19 const Cr = Components.results;
20 const Cu = Components.utils;
21 const CC = Components.Constructor;
23 /**
24 *
25 * Constants
26 *
27 */
29 // Test parameter.
30 const PORT = 8085;
31 const BACKLOG = -1;
33 // Some binary data to send.
34 const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0],
35 DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length),
36 TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER),
37 HELLO_WORLD = "hlo wrld. ",
38 BIG_ARRAY = new Array(65539);
40 TYPED_DATA_ARRAY.set(DATA_ARRAY, 0);
42 for (var i_big = 0; i_big < BIG_ARRAY.length; i_big++) {
43 BIG_ARRAY[i_big] = Math.floor(Math.random() * 256);
44 }
46 const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length);
47 const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER);
48 BIG_TYPED_ARRAY.set(BIG_ARRAY);
50 const TCPSocket = new (CC("@mozilla.org/tcp-socket;1",
51 "nsIDOMTCPSocket"))();
53 const gInChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
54 .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
56 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
57 Cu.import("resource://gre/modules/Services.jsm");
59 /**
60 *
61 * Helper functions
62 *
63 */
66 function makeSuccessCase(name) {
67 return function() {
68 do_print('got expected: ' + name);
69 run_next_test();
70 };
71 }
73 function makeJointSuccess(names) {
74 let funcs = {}, successCount = 0;
75 names.forEach(function(name) {
76 funcs[name] = function() {
77 do_print('got expected: ' + name);
78 if (++successCount === names.length)
79 run_next_test();
80 };
81 });
82 return funcs;
83 }
85 function makeFailureCase(name) {
86 return function() {
87 let argstr;
88 if (arguments.length) {
89 argstr = '(args: ' +
90 Array.map(arguments, function(x) { return x.data + ""; }).join(" ") + ')';
91 }
92 else {
93 argstr = '(no arguments)';
94 }
95 do_throw('got unexpected: ' + name + ' ' + argstr);
96 };
97 }
99 function makeExpectData(name, expectedData, fromEvent, callback) {
100 let dataBuffer = fromEvent ? null : [], done = false;
101 let dataBufferView = null;
102 return function(receivedData) {
103 if (receivedData.data) {
104 receivedData = receivedData.data;
105 }
106 let recvLength = receivedData.byteLength !== undefined ?
107 receivedData.byteLength : receivedData.length;
109 if (fromEvent) {
110 if (dataBuffer) {
111 let newBuffer = new ArrayBuffer(dataBuffer.byteLength + recvLength);
112 let newBufferView = new Uint8Array(newBuffer);
113 newBufferView.set(dataBufferView, 0);
114 newBufferView.set(receivedData, dataBuffer.byteLength);
115 dataBuffer = newBuffer;
116 dataBufferView = newBufferView;
117 }
118 else {
119 dataBuffer = receivedData;
120 dataBufferView = new Uint8Array(dataBuffer);
121 }
122 }
123 else {
124 dataBuffer = dataBuffer.concat(receivedData);
125 }
126 do_print(name + ' received ' + recvLength + ' bytes');
128 if (done)
129 do_throw(name + ' Received data event when already done!');
131 let dataView = dataBuffer.byteLength !== undefined ? new Uint8Array(dataBuffer) : dataBuffer;
132 if (dataView.length >= expectedData.length) {
133 // check the bytes are equivalent
134 for (let i = 0; i < expectedData.length; i++) {
135 if (dataView[i] !== expectedData[i]) {
136 do_throw(name + ' Received mismatched character at position ' + i);
137 }
138 }
139 if (dataView.length > expectedData.length)
140 do_throw(name + ' Received ' + dataView.length + ' bytes but only expected ' +
141 expectedData.length + ' bytes.');
143 done = true;
144 if (callback) {
145 callback();
146 } else {
147 run_next_test();
148 }
149 }
150 };
151 }
153 var server = null, sock = null, connectedsock = null, failure_drain = null;
154 var count = 0;
155 /**
156 *
157 * Test functions
158 *
159 */
161 /**
162 * Connect the socket to the server. This test is added as the first
163 * test, and is also added after every test which results in the socket
164 * being closed.
165 */
167 function connectSock() {
168 if (server) {
169 server.close();
170 }
172 var yayFuncs = makeJointSuccess(['serveropen', 'clientopen']);
173 var options = { binaryType: 'arraybuffer' };
175 server = TCPSocket.listen(PORT, options, BACKLOG);
176 server.onconnect = function(socket) {
177 connectedsock = socket;
178 connectedsock.ondata = makeFailureCase('serverdata');
179 connectedsock.onerror = makeFailureCase('servererror');
180 connectedsock.onclose = makeFailureCase('serverclose');
181 yayFuncs.serveropen();
182 };
183 server.onerror = makeFailureCase('error');
184 sock = TCPSocket.open(
185 '127.0.0.1', PORT, options);
186 sock.onopen = yayFuncs.clientopen;
187 sock.ondrain = null;
188 sock.ondata = makeFailureCase('data');
189 sock.onerror = makeFailureCase('error');
190 sock.onclose = makeFailureCase('close');
191 }
193 /**
194 * Connect the socket to the server after the server was closed.
195 * This test is added after test to close the server was conducted.
196 */
197 function openSockInClosingServer() {
198 var success = makeSuccessCase('clientnotopen');
199 var options = { binaryType: 'arraybuffer' };
201 sock = TCPSocket.open(
202 '127.0.0.1', PORT, options);
204 sock.onopen = makeFailureCase('open');
205 sock.onerror = success;
206 }
208 /**
209 * Test that sending a small amount of data works, and that buffering
210 * does not take place for this small amount of data.
211 */
213 function sendDataToServer() {
214 connectedsock.ondata = makeExpectData('serverdata', DATA_ARRAY, true);
215 if (!sock.send(DATA_ARRAY_BUFFER)) {
216 do_throw("send should not have buffered such a small amount of data");
217 }
218 }
220 /**
221 * Test that data sent from the server correctly fires the ondata
222 * callback on the client side.
223 */
225 function receiveDataFromServer() {
226 connectedsock.ondata = makeFailureCase('serverdata');
227 sock.ondata = makeExpectData('data', DATA_ARRAY, true);
229 connectedsock.send(DATA_ARRAY_BUFFER);
230 }
232 /**
233 * Test that when the server closes the connection, the onclose callback
234 * is fired on the client side.
235 */
237 function serverCloses() {
238 // we don't really care about the server's close event, but we do want to
239 // make sure it happened for sequencing purposes.
240 sock.ondata = makeFailureCase('data');
241 sock.onclose = makeFailureCase('close1');
242 connectedsock.onclose = makeFailureCase('close2');
244 server.close();
245 run_next_test();
246 }
248 /**
249 * Test that when the client closes the connection, the onclose callback
250 * is fired on the server side.
251 */
253 function cleanup() {
254 do_print("Cleaning up");
255 sock.onclose = null;
256 connectedsock.onclose = null;
258 server.close();
259 sock.close();
260 if (count == 1){
261 if (!gInChild)
262 Services.prefs.clearUserPref('dom.mozTCPSocket.enabled');
263 }
264 count++;
265 run_next_test();
266 }
267 // - connect, data and events work both ways
268 add_test(connectSock);
270 add_test(sendDataToServer);
272 add_test(receiveDataFromServer);
273 // - server closes on us
274 add_test(serverCloses);
276 // - send and receive after closing server
277 add_test(sendDataToServer);
278 add_test(receiveDataFromServer);
279 // - check a connection refused from client to server after closing server
280 add_test(serverCloses);
282 add_test(openSockInClosingServer);
284 // - clean up
285 add_test(cleanup);
287 // - send and receive in reverse order for client and server
288 add_test(connectSock);
290 add_test(receiveDataFromServer);
292 add_test(sendDataToServer);
294 // - clean up
296 add_test(cleanup);
298 function run_test() {
299 if (!gInChild)
300 Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
302 run_next_test();
303 }