afb490adbc
This CL updates dart:io but not dart:_http. It updates the sdk sources, the patch files, and tests. Change-Id: I64c3da407f09fa2bc6eec582049c4ae3a8afbe6d Reviewed-on: https://dart-review.googlesource.com/52990 Commit-Queue: Zach Anderson <zra@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
153 lines
4.8 KiB
Dart
153 lines
4.8 KiB
Dart
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
//
|
|
// VMOptions=
|
|
// VMOptions=--short_socket_read
|
|
// VMOptions=--short_socket_write
|
|
// VMOptions=--short_socket_read --short_socket_write
|
|
|
|
import "dart:async";
|
|
import "dart:io";
|
|
|
|
import "package:async_helper/async_helper.dart";
|
|
import "package:expect/expect.dart";
|
|
|
|
InternetAddress HOST;
|
|
const CERTIFICATE = "localhost_cert";
|
|
|
|
// This test sends corrupt data in the middle of a secure network connection.
|
|
// This tests the error handling of RawSecureSocket.
|
|
// A RawSocket connection is upgraded to a secure connection, so that we
|
|
// have a reference to the underlying socket. Then we send some
|
|
// unencrypted data on it, in the middle of an encrypted data transfer.
|
|
|
|
// This test creates a server and then connects a client to the server.
|
|
// After connecting, the connection is upgraded to a secure connection.
|
|
// The client writes data to the server, then writes unencrypted data
|
|
// on the underlying socket. When the server gets the unencrypted data,
|
|
// this causes an error in the NSS code. When the NSS code is in debug
|
|
// mode, bad data on the connection can cause an assertion failure, rather
|
|
// than an exception.
|
|
|
|
const messageSize = 1000;
|
|
|
|
List<int> createTestData() {
|
|
List<int> data = new List<int>(messageSize);
|
|
for (int i = 0; i < messageSize; i++) {
|
|
data[i] = i & 0xff;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void verifyTestData(List<int> data) {
|
|
Expect.equals(messageSize, data.length);
|
|
List<int> expected = createTestData();
|
|
for (int i = 0; i < messageSize; i++) {
|
|
Expect.equals(expected[i], data[i]);
|
|
}
|
|
}
|
|
|
|
Future runServer(RawSocket client) {
|
|
final completer = new Completer();
|
|
final dataReceived = new List<int>(messageSize);
|
|
int bytesRead = 0;
|
|
client.writeEventsEnabled = false;
|
|
client.listen((event) {
|
|
switch (event) {
|
|
case RawSocketEvent.read:
|
|
Expect.isTrue(client.available() > 0);
|
|
var buffer = client.read(200);
|
|
dataReceived.setRange(bytesRead, bytesRead + buffer.length, buffer);
|
|
bytesRead += buffer.length;
|
|
if (bytesRead == dataReceived.length) {
|
|
verifyTestData(dataReceived);
|
|
}
|
|
break;
|
|
case RawSocketEvent.write:
|
|
Expect.fail('WRITE event received');
|
|
break;
|
|
case RawSocketEvent.readClosed:
|
|
Expect.fail('READ_CLOSED event received');
|
|
client.shutdown(SocketDirection.send);
|
|
completer.complete(null);
|
|
break;
|
|
}
|
|
}, onError: (e) {
|
|
Expect.isTrue(e is TlsException);
|
|
Expect.isTrue(e.toString().contains(
|
|
'received a record with an incorrect Message Authentication Code'));
|
|
completer.complete(null);
|
|
});
|
|
return completer.future;
|
|
}
|
|
|
|
Future<RawSocket> runClient(List sockets) {
|
|
final RawSocket baseSocket = sockets[0];
|
|
final RawSecureSocket socket = sockets[1];
|
|
final data = createTestData();
|
|
var completer = new Completer();
|
|
void tryComplete() {
|
|
if (completer != null) {
|
|
completer.complete(null);
|
|
completer = null;
|
|
}
|
|
}
|
|
|
|
int bytesWritten = 0;
|
|
socket.listen((event) {
|
|
switch (event) {
|
|
case RawSocketEvent.read:
|
|
Expect.fail('READ event received');
|
|
break;
|
|
case RawSocketEvent.write:
|
|
if (bytesWritten < data.length) {
|
|
bytesWritten += socket.write(data, bytesWritten);
|
|
}
|
|
if (bytesWritten < data.length) {
|
|
socket.writeEventsEnabled = true;
|
|
}
|
|
if (bytesWritten == data.length) {
|
|
baseSocket.write(data, 0, 300);
|
|
socket.shutdown(SocketDirection.send);
|
|
}
|
|
break;
|
|
case RawSocketEvent.readClosed:
|
|
tryComplete();
|
|
break;
|
|
}
|
|
}, onError: (e) {
|
|
Expect.isTrue(e is IOException);
|
|
tryComplete();
|
|
});
|
|
return completer.future;
|
|
}
|
|
|
|
Future<List> connectClient(int port, bool hostnameInConnect) =>
|
|
RawSocket.connect(HOST, port).then((socket) => (hostnameInConnect
|
|
? RawSecureSocket.secure(socket)
|
|
: RawSecureSocket.secure(socket, host: HOST))
|
|
.then((secureSocket) => [socket, secureSocket]));
|
|
|
|
Future test(bool hostnameInConnect) {
|
|
return RawServerSocket.bind(HOST, 0).then((server) {
|
|
server.listen((client) {
|
|
RawSecureSocket.secureServer(client, CERTIFICATE).then((secureClient) {
|
|
Expect.throws(() => client.add([0]));
|
|
return runServer(secureClient);
|
|
}, onError: (e) {
|
|
Expect.isTrue(e is HandshakeException);
|
|
}).whenComplete(server.close);
|
|
});
|
|
return connectClient(server.port, hostnameInConnect).then(runClient);
|
|
});
|
|
}
|
|
|
|
main() {
|
|
asyncStart();
|
|
InternetAddress.lookup("localhost").then((hosts) {
|
|
HOST = hosts.first;
|
|
return Future.wait([test(false), test(true)]);
|
|
}).then((_) => asyncEnd());
|
|
}
|