OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 abstract class SecureServerSocket implements ServerSocket { | 7 /** |
8 /** | 8 * The [SecureServerSocket] is a server socket, providing a stream of high-level |
9 * Constructs a new secure server socket, binds it to a given address | 9 * [Socket]s. |
10 * and port, and listens on it. Incoming client connections are | 10 * |
11 * promoted to secure connections, using the server certificate given by | 11 * See [SecureSocket] for more info. |
12 * certificate_name. The bindAddress must be given as a numeric address, | 12 */ |
13 * not a host name. The certificate name is the distinguished name (DN) of | 13 class SecureServerSocket extends Stream<SecureSocket> implements ServerSocket { |
14 * the certificate, such as "CN=localhost" or "CN=myserver.mydomain.com". | 14 final RawSecureServerSocket _socket; |
15 * The certificate is looked up in the NSS certificate database set by | 15 |
16 * SecureSocket.setCertificateDatabase. | 16 SecureServerSocket._(RawSecureServerSocket this._socket); |
| 17 |
| 18 /** |
| 19 * Returns a future for a [SecureServerSocket]. When the future |
| 20 * completes the server socket is bound to the given [address] and |
| 21 * [port] and has started listening on it. |
| 22 * |
| 23 * If [port] has the value [:0:] (the default) an ephemeral port will |
| 24 * be chosen by the system. The actual port used can be retrieved |
| 25 * using the [port] getter. |
| 26 * |
| 27 * If [backlog] has the value of [:0:] a reasonable value will be |
| 28 * chosen by the system. |
| 29 * |
| 30 * Incoming client connections are promoted to secure connections, using |
| 31 * the server certificate given by [certificateName]. |
| 32 * |
| 33 * [address] must be given as a numeric address, not a host name. |
| 34 * |
| 35 * [certificateName] is the nickname or the distinguished name (DN) of |
| 36 * the certificate in the certificate database. It is looked up in the |
| 37 * NSS certificate database set by SecureSocket.setCertificateDatabase. |
| 38 * If [certificateName] contains "CN=", it is assumed to be a distinguished |
| 39 * name. Otherwise, it is looked up as a nickname. |
| 40 * |
| 41 * To request or require that clients authenticate by providing an SSL (TLS) |
| 42 * client certificate, set the optional parameter [requestClientCertificate] |
| 43 * or [requireClientCertificate] to true. Requiring a certificate implies |
| 44 * requesting a certificate, so one doesn't need to set both to true. |
| 45 * To check whether a client certificate was received, check |
| 46 * SecureSocket.peerCertificate after connecting. If no certificate |
| 47 * was received, the result will be null. |
| 48 */ |
| 49 static Future<SecureServerSocket> bind( |
| 50 String address, |
| 51 int port, |
| 52 int backlog, |
| 53 String certificateName, |
| 54 {bool requestClientCertificate: false, |
| 55 bool requireClientCertificate: false}) { |
| 56 return RawSecureServerSocket.bind( |
| 57 address, |
| 58 port, |
| 59 backlog, |
| 60 certificateName, |
| 61 requestClientCertificate: requestClientCertificate, |
| 62 requireClientCertificate: requireClientCertificate).then( |
| 63 (serverSocket) => new SecureServerSocket._(serverSocket)); |
| 64 } |
| 65 |
| 66 StreamSubscription<SecureSocket> listen(void onData(SecureSocket socket), |
| 67 {void onError(AsyncError error), |
| 68 void onDone(), |
| 69 bool unsubscribeOnError}) { |
| 70 return _socket.map((rawSocket) => new SecureSocket._(rawSocket)) |
| 71 .listen(onData, |
| 72 onError: onError, |
| 73 onDone: onDone, |
| 74 unsubscribeOnError: unsubscribeOnError); |
| 75 } |
| 76 |
| 77 /** |
| 78 * Returns the port used by this socket. |
| 79 */ |
| 80 int get port => _socket.port; |
| 81 |
| 82 /** |
| 83 * Closes the socket. |
| 84 */ |
| 85 void close() => _socket.close(); |
| 86 } |
| 87 |
| 88 |
| 89 /** |
| 90 * The RawSecureServerSocket is a server socket, providing a stream of low-level |
| 91 * [RawSecureSocket]s. |
| 92 * |
| 93 * See [RawSecureSocket] for more info. |
| 94 */ |
| 95 class RawSecureServerSocket extends Stream<RawSecureSocket> { |
| 96 RawServerSocket _socket; |
| 97 StreamController<RawSecureSocket> _controller; |
| 98 StreamSubscription<RawSocket> _subscription; |
| 99 final String certificateName; |
| 100 final bool requestClientCertificate; |
| 101 final bool requireClientCertificate; |
| 102 bool _closed = false; |
| 103 |
| 104 RawSecureServerSocket._(RawServerSocket serverSocket, |
| 105 String this.certificateName, |
| 106 bool this.requestClientCertificate, |
| 107 bool this.requireClientCertificate) { |
| 108 _socket = serverSocket; |
| 109 _controller = new StreamController<RawSecureSocket>( |
| 110 onPauseStateChange: _onPauseStateChange, |
| 111 onSubscriptionStateChange: _onSubscriptionStateChange); |
| 112 } |
| 113 |
| 114 /** |
| 115 * Returns a future for a [RawSecureServerSocket]. When the future |
| 116 * completes the server socket is bound to the given [address] and |
| 117 * [port] and has started listening on it. |
| 118 * |
| 119 * If [port] has the value [:0:] (the default) an ephemeral port will |
| 120 * be chosen by the system. The actual port used can be retrieved |
| 121 * using the [port] getter. |
| 122 * |
| 123 * If [backlog] has the value of [:0:] a reasonable value will be |
| 124 * chosen by the system. |
| 125 * |
| 126 * Incoming client connections are promoted to secure connections, |
| 127 * using the server certificate given by [certificateName]. |
| 128 * |
| 129 * [address] must be given as a numeric address, not a host name. |
| 130 * |
| 131 * [certificateName] is the nickname or the distinguished name (DN) of |
| 132 * the certificate in the certificate database. It is looked up in the |
| 133 * NSS certificate database set by SecureSocket.setCertificateDatabase. |
| 134 * If [certificateName] contains "CN=", it is assumed to be a distinguished |
| 135 * name. Otherwise, it is looked up as a nickname. |
17 * | 136 * |
18 * To request or require that clients authenticate by providing an SSL (TLS) | 137 * To request or require that clients authenticate by providing an SSL (TLS) |
19 * client certificate, set the optional parameters requestClientCertificate or | 138 * client certificate, set the optional parameters requestClientCertificate or |
20 * requireClientCertificate to true. Require implies request, so one doesn't | 139 * requireClientCertificate to true. Require implies request, so one doesn't |
21 * need to specify both. To check whether a client certificate was received, | 140 * need to specify both. To check whether a client certificate was received, |
22 * check SecureSocket.peerCertificate after connecting. If no certificate | 141 * check SecureSocket.peerCertificate after connecting. If no certificate |
23 * was received, the result will be null. | 142 * was received, the result will be null. |
24 */ | 143 */ |
25 factory SecureServerSocket(String bindAddress, | 144 static Future<RawSecureServerSocket> bind( |
26 int port, | 145 String address, |
27 int backlog, | 146 int port, |
28 String certificate_name, | 147 int backlog, |
29 {bool requestClientCertificate: false, | 148 String certificateName, |
30 bool requireClientCertificate: false}) { | 149 {bool requestClientCertificate: false, |
31 return new _SecureServerSocket(bindAddress, | 150 bool requireClientCertificate: false}) { |
32 port, | 151 return RawServerSocket.bind(address, port, backlog) |
33 backlog, | 152 .then((serverSocket) => new RawSecureServerSocket._( |
34 certificate_name, | 153 serverSocket, |
35 requestClientCertificate, | 154 certificateName, |
36 requireClientCertificate); | 155 requestClientCertificate, |
37 } | 156 requireClientCertificate)); |
38 } | 157 } |
39 | 158 |
40 | 159 StreamSubscription<RawSecureSocket> listen(void onData(RawSecureSocket s), |
41 class _SecureServerSocket implements SecureServerSocket { | 160 {void onError(AsyncError error), |
42 | 161 void onDone(), |
43 _SecureServerSocket(String bindAddress, | 162 bool unsubscribeOnError}) { |
44 int port, | 163 return _controller.stream.listen(onData, |
45 int backlog, | 164 onError: onError, |
46 String this.certificate_name, | 165 onDone: onDone, |
47 bool this.requestClientCertificate, | 166 unsubscribeOnError: unsubscribeOnError); |
48 bool this.requireClientCertificate) { | |
49 socket = new ServerSocket(bindAddress, port, backlog); | |
50 socket.onConnection = this._onConnectionHandler; | |
51 } | |
52 | |
53 void set onConnection(void callback(Socket connection)) { | |
54 _onConnectionCallback = callback; | |
55 } | |
56 | |
57 void set onError(void callback(e)) { | |
58 socket.onError = callback; | |
59 } | 167 } |
60 | 168 |
61 /** | 169 /** |
62 * Returns the port used by this socket. | 170 * Returns the port used by this socket. |
63 */ | 171 */ |
64 int get port => socket.port; | 172 int get port => _socket.port; |
65 | 173 |
66 /** | 174 /** |
67 * Closes the socket. | 175 * Closes the socket. |
68 */ | 176 */ |
69 void close() { | 177 void close() { |
70 socket.close(); | 178 _closed = true; |
71 } | 179 _socket.close(); |
72 | 180 } |
73 void _onConnectionHandler(Socket connection) { | 181 |
74 if (_onConnectionCallback == null) { | 182 void _onData(RawSocket connection) { |
75 connection.close(); | 183 _RawSecureSocket.connect( |
76 throw new SocketIOException( | |
77 "SecureServerSocket with no onConnection callback connected to"); | |
78 } | |
79 if (certificate_name == null) { | |
80 connection.close(); | |
81 throw new SocketIOException( | |
82 "SecureServerSocket with server certificate not set connected to"); | |
83 } | |
84 var secure_connection = new _SecureSocket( | |
85 connection.remoteHost, | 184 connection.remoteHost, |
86 connection.remotePort, | 185 connection.remotePort, |
87 certificate_name, | 186 certificateName, |
88 is_server: true, | 187 is_server: true, |
89 socket: connection, | 188 socket: connection, |
90 requestClientCertificate: requestClientCertificate, | 189 requestClientCertificate: requestClientCertificate, |
91 requireClientCertificate: requireClientCertificate); | 190 requireClientCertificate: requireClientCertificate) |
92 _onConnectionCallback(secure_connection); | 191 .then((RawSecureSocket secureConnection) { |
93 } | 192 if (_closed) { |
94 | 193 secureConnection.close(); |
95 ServerSocket socket; | 194 } else { |
96 var _onConnectionCallback; | 195 _controller.add(secureConnection); |
97 final String certificate_name; | 196 } |
98 final bool requestClientCertificate; | 197 }).catchError((e) { |
99 final bool requireClientCertificate; | 198 if (_closed) { |
| 199 throw e; |
| 200 } else { |
| 201 _controller.signalError(e); |
| 202 close(); |
| 203 } |
| 204 }); |
| 205 } |
| 206 |
| 207 void _onError(e) { |
| 208 _controller.signalError(e); |
| 209 close(); |
| 210 } |
| 211 |
| 212 void _onDone() { |
| 213 _controller.close(); |
| 214 } |
| 215 |
| 216 void _onPauseStateChange() { |
| 217 if (_controller.isPaused) { |
| 218 _subscription.pause(); |
| 219 } else { |
| 220 _subscription.resume(); |
| 221 } |
| 222 } |
| 223 |
| 224 void _onSubscriptionStateChange() { |
| 225 if (_controller.hasSubscribers) { |
| 226 _subscription = _socket.listen(_onData, |
| 227 onDone: _onDone, |
| 228 onError: _onError); |
| 229 } else { |
| 230 close(); |
| 231 } |
| 232 } |
100 } | 233 } |
| 234 |
| 235 |
OLD | NEW |