Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library http_multi_server; | 5 library http_multi_server; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'src/multi_headers.dart'; | 10 import 'src/multi_headers.dart'; |
| 11 import 'src/utils.dart'; | 11 import 'src/utils.dart'; |
| 12 | 12 |
| 13 /// The error code for an error caused by a port already being in use. | |
| 14 final _addressInUseErrno = _computeAddressInUseErrno(); | |
| 15 int _computeAddressInUseErrno() { | |
| 16 if (Platform.isWindows) return 10048; | |
| 17 if (Platform.isMacOS) return 48; | |
| 18 assert(Platform.isLinux); | |
| 19 return 98; | |
| 20 } | |
| 21 | |
| 13 /// An implementation of `dart:io`'s [HttpServer] that wraps multiple servers | 22 /// An implementation of `dart:io`'s [HttpServer] that wraps multiple servers |
| 14 /// and forwards methods to all of them. | 23 /// and forwards methods to all of them. |
| 15 /// | 24 /// |
| 16 /// This is useful for serving the same application on multiple network | 25 /// This is useful for serving the same application on multiple network |
| 17 /// interfaces while still having a unified way of controlling the servers. In | 26 /// interfaces while still having a unified way of controlling the servers. In |
| 18 /// particular, it supports serving on both the IPv4 and IPv6 loopback addresses | 27 /// particular, it supports serving on both the IPv4 and IPv6 loopback addresses |
| 19 /// using [HttpMultiServer.loopback]. | 28 /// using [HttpMultiServer.loopback]. |
| 20 class HttpMultiServer extends StreamView<HttpRequest> implements HttpServer { | 29 class HttpMultiServer extends StreamView<HttpRequest> implements HttpServer { |
| 21 /// The wrapped servers. | 30 /// The wrapped servers. |
| 22 final Set<HttpServer> _servers; | 31 final Set<HttpServer> _servers; |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 127 var supportsIpV6 = results[0]; | 136 var supportsIpV6 = results[0]; |
| 128 var v4Server = results[1]; | 137 var v4Server = results[1]; |
| 129 | 138 |
| 130 if (!supportsIpV6) return v4Server; | 139 if (!supportsIpV6) return v4Server; |
| 131 | 140 |
| 132 // Reuse the IPv4 server's port so that if [port] is 0, both servers use | 141 // Reuse the IPv4 server's port so that if [port] is 0, both servers use |
| 133 // the same ephemeral port. | 142 // the same ephemeral port. |
| 134 return bind(InternetAddress.LOOPBACK_IP_V6, v4Server.port) | 143 return bind(InternetAddress.LOOPBACK_IP_V6, v4Server.port) |
| 135 .then((v6Server) { | 144 .then((v6Server) { |
| 136 return new HttpMultiServer([v4Server, v6Server]); | 145 return new HttpMultiServer([v4Server, v6Server]); |
| 146 }).catchError((error) { | |
| 147 if (error is! SocketException) throw error; | |
| 148 if (error.osError.errno != _addressInUseErrno) throw error; | |
| 149 if (port != 0) throw error; | |
| 150 | |
| 151 // A port being available on IPv4 doesn't necessarily mean that the same | |
| 152 // port is available on IPv6. If it's not (which is rare in practice), | |
| 153 // we try again until we find one that's available on both. | |
| 154 v4Server.close(); | |
| 155 return _loopback(port, bind); | |
|
skybrian
2015/03/09 22:34:57
Retrying forever will cause the program to spin wh
nweiz
2015/03/09 23:38:15
https://codereview.chromium.org/992843002/
| |
| 137 }); | 156 }); |
| 138 }); | 157 }); |
| 139 } | 158 } |
| 140 | 159 |
| 141 Future close({bool force: false}) => | 160 Future close({bool force: false}) => |
| 142 Future.wait(_servers.map((server) => server.close(force: force))); | 161 Future.wait(_servers.map((server) => server.close(force: force))); |
| 143 | 162 |
| 144 /// Returns an HttpConnectionsInfo object summarizing the total number of | 163 /// Returns an HttpConnectionsInfo object summarizing the total number of |
| 145 /// current connections handled by all the servers. | 164 /// current connections handled by all the servers. |
| 146 HttpConnectionsInfo connectionsInfo() { | 165 HttpConnectionsInfo connectionsInfo() { |
| 147 var info = new HttpConnectionsInfo(); | 166 var info = new HttpConnectionsInfo(); |
| 148 for (var server in _servers) { | 167 for (var server in _servers) { |
| 149 var subInfo = server.connectionsInfo(); | 168 var subInfo = server.connectionsInfo(); |
| 150 info.total += subInfo.total; | 169 info.total += subInfo.total; |
| 151 info.active += subInfo.active; | 170 info.active += subInfo.active; |
| 152 info.idle += subInfo.idle; | 171 info.idle += subInfo.idle; |
| 153 info.closing += subInfo.closing; | 172 info.closing += subInfo.closing; |
| 154 } | 173 } |
| 155 return info; | 174 return info; |
| 156 } | 175 } |
| 157 } | 176 } |
| OLD | NEW |