1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // net/tools/testserver/testserver.py is picky about the format of what it
6 // calls its "echo" messages. One might go so far as to mutter to oneself that
7 // it isn't an echo server at all.
9 // The response is based on the request but obfuscated using a random key.
10 const request = "0100000005320000005hello";
11 var expectedResponsePattern = /0100000005320000005.{11}/;
12 const http_get = "GET test.html HTTP/1.0\r\n\r\n";
13 var expectedHTTPPattern = /HTTP.1.0 200 OK/;
22 var protocol = "none";
24 var https_socketId = 0;
25 var echoDataSent = false;
26 var succeeded = false;
29 // Keys are socketIds. Values are inner dictionaries with two keys: onReceive,
30 // onReceiveError. Both are functions.
31 var receive_dispatcher = {}
33 // Many thanks to Dennis for his StackOverflow answer: http://goo.gl/UDanx
34 // Since amended to handle BlobBuilder deprecation.
35 function string2ArrayBuffer(string, callback) {
36 var blob = new Blob([string]);
37 var f = new FileReader();
38 f.onload = function(e) {
39 callback(e.target.result);
41 f.readAsArrayBuffer(blob);
44 function arrayBuffer2String(buf, callback) {
45 var blob = new Blob([new Uint8Array(buf)]);
46 var f = new FileReader();
47 f.onload = function(e) {
48 callback(e.target.result);
53 function dispatchSocketReceive(receiveInfo) {
54 if (receive_dispatcher[receiveInfo.socketId] !== undefined) {
55 receive_dispatcher[receiveInfo.socketId].onReceive(receiveInfo);
57 console.log("dispatchSocketReceive: No handler for socket " +
58 receiveInfo.socketId);
62 function dispatchSocketReceiveError(receiveErrorInfo) {
63 if (receive_dispatcher[receiveErrorInfo.socketId] !== undefined) {
64 receive_dispatcher[receiveErrorInfo.socketId].onReceiveError(
67 console.log("dispatchSocketReceiveError: No handler for socket " +
68 receiveErrorInfo.socketId);
72 var testSocketCreation = function() {
73 function onCreate(socketInfo) {
74 function onGetInfo(info) {
75 chrome.test.assertFalse(info.connected);
77 if (info.peerAddress || info.peerPort) {
78 chrome.test.fail('Unconnected socket should not have peer');
80 if (info.localAddress || info.localPort) {
81 chrome.test.fail('Unconnected socket should not have local binding');
84 chrome.sockets.tcp.close(socketInfo.socketId, function() {
85 chrome.sockets.tcp.getInfo(socketInfo.socketId, function(info) {
86 chrome.test.assertEq(undefined, info);
87 chrome.test.succeed();
92 chrome.test.assertTrue(socketInfo.socketId > 0);
94 // Obtaining socket information before a connect() call should be safe, but
95 // return empty values.
96 chrome.sockets.tcp.getInfo(socketInfo.socketId, onGetInfo);
99 chrome.sockets.tcp.create({}, onCreate);
102 var testSending = function() {
105 echoDataSent = false;
108 setTimeout(waitForBlockingOperation, 1000);
112 function createSocket() {
113 chrome.sockets.tcp.create({
117 }, onCreateComplete);
120 function onCreateComplete(socketInfo) {
121 console.log("onCreateComplete");
122 tcp_socketId = socketInfo.socketId;
123 chrome.test.assertTrue(tcp_socketId > 0, "failed to create socket");
125 console.log("add event listeners");
126 receive_dispatcher[tcp_socketId] = {
127 onReceive: onSocketReceive,
128 onReceiveError: onSocketReceiveError
131 chrome.sockets.tcp.getInfo(tcp_socketId, onGetInfoAfterCreateComplete);
134 function onGetInfoAfterCreateComplete(result) {
135 console.log("onGetInfoAfterCreateComplete");
136 chrome.test.assertTrue(!result.localAddress,
137 "Socket should not have local address");
138 chrome.test.assertTrue(!result.localPort,
139 "Socket should not have local port");
140 chrome.test.assertTrue(!result.peerAddress,
141 "Socket should not have peer address");
142 chrome.test.assertTrue(!result.peerPort,
143 "Socket should not have peer port");
144 chrome.test.assertFalse(result.connected, "Socket should not be connected");
146 chrome.test.assertEq("test", result.name, "Socket name did not persist");
147 chrome.test.assertTrue(result.persistent,
148 "Socket should be persistent");
149 chrome.test.assertEq(104, result.bufferSize, "Buffer size did not persist");
150 chrome.test.assertFalse(result.paused, "Socket should not be paused");
152 chrome.sockets.tcp.update(tcp_socketId, {
156 }, onUpdateComplete);
159 function onUpdateComplete() {
160 console.log("onUpdateComplete");
161 chrome.sockets.tcp.getInfo(tcp_socketId, onGetInfoAfterUpdateComplete);
164 function onGetInfoAfterUpdateComplete(result) {
165 console.log("onGetInfoAfterUpdateComplete");
166 chrome.test.assertTrue(!result.localAddress,
167 "Socket should not have local address");
168 chrome.test.assertTrue(!result.localPort,
169 "Socket should not have local port");
170 chrome.test.assertTrue(!result.peerAddress,
171 "Socket should not have peer address");
172 chrome.test.assertTrue(!result.peerPort,
173 "Socket should not have peer port");
174 chrome.test.assertFalse(result.connected, "Socket should not be connected");
176 chrome.test.assertEq("test2", result.name, "Socket name did not persist");
177 chrome.test.assertFalse(result.persistent,
178 "Socket should not be persistent");
179 chrome.test.assertEq(2048, result.bufferSize,
180 "Buffer size did not persist");
181 chrome.test.assertFalse(result.paused, "Socket should not be paused");
183 chrome.sockets.tcp.connect(tcp_socketId, tcp_address, tcp_port,
187 function onConnectComplete(result) {
188 console.log("onConnectComplete");
189 chrome.test.assertEq(0, result,
190 "Connect failed with error " + result);
192 chrome.sockets.tcp.getInfo(tcp_socketId, onGetInfoAfterConnectComplete);
195 function onGetInfoAfterConnectComplete(result) {
196 console.log("onGetInfoAfterConnectComplete");
197 chrome.test.assertTrue(!!result.localAddress,
198 "Bound socket should always have local address");
199 chrome.test.assertTrue(!!result.localPort,
200 "Bound socket should always have local port");
202 // NOTE: We're always called with 'localhost', but getInfo will only return
204 chrome.test.assertEq(result.peerAddress, "127.0.0.1",
205 "Peer addresss should be the listen server");
206 chrome.test.assertEq(result.peerPort, tcp_port,
207 "Peer port should be the listen server");
208 chrome.test.assertTrue(result.connected, "Socket should be connected");
210 chrome.sockets.tcp.setPaused(tcp_socketId, true, onSetPausedComplete);
213 function onSetPausedComplete() {
214 console.log("onSetPausedComplete");
215 chrome.sockets.tcp.getInfo(tcp_socketId, onGetInfoAfterSetPausedComplete);
218 function onGetInfoAfterSetPausedComplete(result) {
219 console.log("onGetInfoAfterSetPausedComplete");
220 chrome.test.assertTrue(result.paused, "Socket should be paused");
221 chrome.sockets.tcp.setPaused(tcp_socketId, false, onUnpauseComplete);
224 function onUnpauseComplete() {
225 console.log("onUnpauseComplete");
226 chrome.sockets.tcp.getInfo(tcp_socketId, onGetInfoAfterUnpauseComplete);
229 function onGetInfoAfterUnpauseComplete(result) {
230 console.log("onGetInfoAfterUnpauseComplete");
231 chrome.test.assertFalse(result.paused, "Socket should not be paused");
232 chrome.sockets.tcp.setNoDelay(tcp_socketId, true, onSetNoDelayComplete);
235 function onSetNoDelayComplete(result) {
236 console.log("onSetNoDelayComplete");
238 chrome.test.fail("setNoDelay failed for TCP: " +
239 "result=" + result + ", " +
240 "lastError=" + chrome.runtime.lastError.message);
242 chrome.sockets.tcp.setKeepAlive(
243 tcp_socketId, true, 1000, onSetKeepAliveComplete);
246 function onSetKeepAliveComplete(result) {
247 console.log("onSetKeepAliveComplete");
249 chrome.test.fail("setKeepAlive failed for TCP: " +
250 "result=" + result + ", " +
251 "lastError=" + chrome.runtime.lastError.message);
254 string2ArrayBuffer(request, function(arrayBuffer) {
256 chrome.sockets.tcp.send(tcp_socketId, arrayBuffer, onSendComplete);
260 function onSendComplete(sendInfo) {
261 console.log("onSendComplete: " + sendInfo.bytesSent + " bytes.");
262 chrome.test.assertEq(0, sendInfo.resultCode, "Send failed.");
263 chrome.test.assertTrue(sendInfo.bytesSent > 0,
264 "Send didn't write bytes.");
265 bytesSent += sendInfo.bytesSent;
268 function onSocketReceive(receiveInfo) {
269 console.log("onSocketReceive");
270 chrome.test.assertEq(tcp_socketId, receiveInfo.socketId);
271 arrayBuffer2String(receiveInfo.data, function(s) {
272 dataAsString = s; // save this for error reporting
273 var match = !!s.match(expectedResponsePattern);
274 chrome.test.assertTrue(match, "Received data does not match.");
275 console.log("echo data received, closing socket");
276 chrome.sockets.tcp.close(tcp_socketId, onCloseComplete);
280 function onSocketReceiveError(receiveErrorInfo) {
281 // Note: Once we have sent the "echo" message, the echo server sends back
282 // the "echo" response and closes the connection right away. This means
283 // we get a "connection closed" error very quickly after sending our
284 // message. This is why we ignore errors from that point on.
288 console.log("onSocketReceiveError");
289 chrome.test.fail("Receive error on socket " + receiveErrorInfo.socketId +
290 ": result code=" + receiveErrorInfo.resultCode);
293 function onCloseComplete() {
294 console.log("onCloseComplete");
296 chrome.test.succeed();
301 var testSecure = function () {
302 var request_sent = false;
305 setTimeout(waitForBlockingOperation, 1000);
307 // Run the test a few times. First with misuse_testing=MISUSE_NONE,
308 // to test that the API works correctly when used properly. Then
309 // with different values of misuse_mode, test that the API does
310 // not malfunction when used improperly. Upon success, each misuse
311 // must close the socket and call onCloseComplete().
313 var MISUSE_SECURE_PENDING_READ = 1;
314 var MISUSE_LAST = MISUSE_SECURE_PENDING_READ;
315 var misuse_mode = MISUSE_NONE;
317 chrome.sockets.tcp.create({}, onCreateComplete);
319 function onCreateComplete(socketInfo) {
320 https_socketId = socketInfo.socketId;
321 receive_dispatcher[https_socketId] = {
322 onReceive: onSocketReceive,
323 onReceiveError: onSocketReceiveError
326 chrome.test.assertTrue(https_socketId > 0, "failed to create socket");
327 if (misuse_mode == MISUSE_SECURE_PENDING_READ) {
328 // Don't pause the socket. This will let the sockets runtime
329 // keep a pending read on it.
330 console.log("HTTPS onCreateComplete: in MISUSE_SECURE_PENDING_READ " +
331 "mode, skipping setPaused(false).");
334 chrome.sockets.tcp.setPaused(https_socketId, true, onPausedComplete);
338 function onPausedComplete() {
339 console.log("HTTPS onPausedComplete. Connecting to " + https_address + ":" +
341 chrome.sockets.tcp.connect(https_socketId, https_address, https_port,
345 function onConnectComplete(result) {
346 console.log("HTTPS onConnectComplete");
347 chrome.test.assertEq(0, result,
348 "Connect failed with error " + result);
349 chrome.sockets.tcp.secure(https_socketId, null, onSecureComplete);
352 function onSecureComplete(result) {
353 console.log("HTTPS onSecureComplete(" + result + ")");
354 if (misuse_mode == MISUSE_SECURE_PENDING_READ) {
355 chrome.test.assertFalse(result == 0,
356 "Secure should have failed when a read " +
357 "was pending (" + result + ")");
358 chrome.sockets.tcp.close(https_socketId, onCloseComplete);
360 chrome.test.assertEq(0, result,
361 "Secure failed with error " + result);
362 chrome.sockets.tcp.setPaused(https_socketId, false, onUnpauseComplete);
366 function onUnpauseComplete() {
367 console.log("HTTPS onUnpauseComplete");
368 string2ArrayBuffer(http_get, function(arrayBuffer) {
370 chrome.sockets.tcp.send(https_socketId, arrayBuffer, onSendComplete);
374 function onSendComplete(sendInfo) {
375 console.log("HTTPS onSendComplete: " + sendInfo.bytesSent + " bytes.");
376 chrome.test.assertEq(0, sendInfo.resultCode, "Send failed.");
377 chrome.test.assertTrue(sendInfo.bytesSent > 0,
378 "Send didn't write bytes.");
379 bytesSent += sendInfo.bytesSent;
382 function onSocketReceive(receiveInfo) {
383 console.log("HTTPS onSocketReceive");
384 chrome.test.assertEq(https_socketId, receiveInfo.socketId);
385 arrayBuffer2String(receiveInfo.data, function(s) {
386 // we will get more data than we care about. We only care about the
387 // first segment of data (the HTTP 200 code). Ignore the rest, which
388 // won't match the pattern.
389 if (succeeded == false) {
390 dataAsString = s; // for waitForBlockingOperation().
391 console.log("HTTPS receive: got " + s);
392 var match = !!s.match(expectedHTTPPattern);
393 chrome.test.assertTrue(match, "Received data does not match.");
394 console.log("HTTPS response received, closing socket.");
395 chrome.sockets.tcp.close(https_socketId, onCloseComplete);
401 function onSocketReceiveError(receiveErrorInfo) {
402 console.log("HTTPS onSocketReceiveError");
406 chrome.test.fail("Receive error on socket " + receiveErrorInfo.socketId +
407 ": result code=" + receiveErrorInfo.resultCode);
410 function onCloseComplete() {
411 console.log("HTTPS Test Succeeded");
412 if (misuse_mode == MISUSE_LAST) {
413 // The test has run in all misuse modes.
414 chrome.test.succeed();
416 // Run the test again in the next misuse mode.
418 chrome.sockets.tcp.create({}, onCreateComplete);
423 function waitForBlockingOperation() {
424 if (++waitCount < 10) {
425 setTimeout(waitForBlockingOperation, 1000);
427 // We weren't able to succeed in the given time.
428 chrome.test.fail("Operations didn't complete after " + waitCount + " " +
429 "seconds. Response so far was <" + dataAsString + ">.");
433 var onMessageReply = function(message) {
434 var components = message.split(',');
436 for (var i = 0; i < components.length; ++i) {
437 var parts = components[i].split(":");
438 var test_type = parts[0];
439 if (test_type == 'tcp') {
440 tcp_address = parts[1];
441 tcp_port = parseInt(parts[2]);
442 console.log("Running tests for TCP, echo server " +
443 tcp_address + ":" + tcp_port);
444 tests = tests.concat([testSocketCreation, testSending]);
445 } else if (test_type == 'https') {
446 https_address = parts[1];
447 https_port = parseInt(parts[2]);
448 console.log("Running tests for HTTPS, server " +
449 https_address + ":" + https_port);
450 tests = tests.concat([testSecure]);
452 chrome.test.fail("Invalid test type: " + test_type);
455 // Setup the suite-wide event listeners.
456 chrome.sockets.tcp.onReceive.addListener(dispatchSocketReceive);
457 chrome.sockets.tcp.onReceiveError.addListener(dispatchSocketReceiveError);
459 chrome.test.runTests(tests);
462 // Find out which protocol we're supposed to test, and which echo server we
463 // should be using, then kick off the tests.
464 chrome.test.sendMessage("info_please", onMessageReply);