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
);