Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library http_multi_server; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 import 'dart:io'; | |
| 9 | |
| 10 import 'src/utils.dart'; | |
| 11 | |
| 12 /// An implementation of `dart:io`'s [HttpServer] that wraps multiple servers | |
| 13 /// and forwards methods to all of them. | |
| 14 /// | |
| 15 /// This is useful for serving the same application on multiple network | |
| 16 /// interfaces while still having a unified way of controlling the servers. In | |
| 17 /// particular, it supports serving on both the IPv4 and IPv6 loopback addresses | |
| 18 /// using [HttpMultiServer.loopback]. | |
| 19 class HttpMultiServer extends StreamView<HttpRequest> implements HttpServer { | |
| 20 /// The wrapped servers. | |
| 21 final Set<HttpServer> _servers; | |
| 22 | |
| 23 String get serverHeader => _servers.first.serverHeader; | |
| 24 set serverHeader(String value) { | |
| 25 for (var server in _servers) { | |
| 26 server.serverHeader = value; | |
| 27 } | |
| 28 } | |
| 29 | |
| 30 Duration get idleTimeout => _servers.first.idleTimeout; | |
| 31 set idleTimeout(Duration value) { | |
| 32 for (var server in _servers) { | |
| 33 server.idleTimeout = value; | |
| 34 } | |
| 35 } | |
| 36 | |
| 37 /// Returns the port that one of the wrapped servers is listening on. | |
| 38 /// | |
| 39 /// If the wrapped servers are listening on different ports, it's not defined | |
| 40 /// which port is returned. | |
| 41 int get port => _servers.first.port; | |
| 42 | |
| 43 /// Returns the address that one of the wrapped servers is listening on. | |
| 44 /// | |
| 45 /// If the wrapped servers are listening on different addresses, it's not | |
| 46 /// defined which address is returned. | |
| 47 InternetAddress get address => _servers.first.address; | |
| 48 | |
| 49 set sessionTimeout(int value) { | |
| 50 for (var server in _servers) { | |
| 51 server.sessionTimeout = value; | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 /// Creates an [HttpMultiServer] wrapping [servers]. | |
| 56 /// | |
| 57 /// All [servers] should have the same configuration and none should be | |
| 58 /// listened to when this is called. | |
| 59 HttpMultiServer(Iterable<HttpServer> servers) | |
| 60 : _servers = servers.toSet(), | |
| 61 super(mergeStreams(servers)); | |
| 62 | |
| 63 /// Creates an [HttpServer] listening on all available loopback addresses for | |
| 64 /// this computer. | |
| 65 /// | |
| 66 /// If this computer supports both IPv4 and IPv6, this will return an | |
|
Bob Nystrom
2014/06/04 23:58:17
"will return" -> "returns", and below.
nweiz
2014/06/05 00:36:09
Done.
| |
| 67 /// [HttpMultiServer] listening to [port] on both loopback addresses. | |
| 68 /// Otherwise, it will return a normal [HttpServer] listening only on the IPv4 | |
| 69 /// address. | |
| 70 /// | |
| 71 /// If [port] is 0, the same ephemeral port is used for both the IPv4 and IPv6 | |
| 72 /// addresses. | |
| 73 static Future<HttpServer> loopback(int port, {int backlog}) { | |
| 74 if (backlog == null) backlog = 0; | |
| 75 | |
| 76 return _loopback(port, (address, port) => | |
| 77 HttpServer.bind(address, port, backlog: backlog)); | |
| 78 } | |
| 79 | |
| 80 /// Like [loopback], but supports HTTPS requests. | |
| 81 /// | |
| 82 /// The certificate with nickname or distinguished name (DN) [certificateName] | |
| 83 /// is looked up in the certificate database, and is used as the server | |
| 84 /// certificate. If [requestClientCertificate] is true, the server will | |
| 85 /// request clients to authenticate with a client certificate. | |
| 86 static Future<HttpServer> loopbackSecure(int port, {int backlog, | |
| 87 String certificateName, bool requestClientCertificate: false}) { | |
| 88 if (backlog == null) backlog = 0; | |
| 89 | |
| 90 return _loopback(port, (address, port) => | |
| 91 HttpServer.bindSecure(address, port, backlog: backlog, | |
| 92 certificateName: certificateName, | |
| 93 requestClientCertificate: requestClientCertificate)); | |
| 94 } | |
| 95 | |
| 96 /// A helper method for initializing loopback servers. | |
| 97 /// | |
| 98 /// [bind] should forward to either [HttpServer.bind] or | |
| 99 /// [HttpServer.bindSecure]. | |
| 100 static Future<HttpServer> _loopback(int port, | |
| 101 Future<HttpServer> bind(InternetAddress address, int port)) { | |
| 102 return Future.wait([ | |
| 103 supportsIpV6, | |
| 104 bind(InternetAddress.LOOPBACK_IP_V4, port) | |
| 105 ]).then((results) { | |
| 106 var supportsIpV6 = results[0]; | |
| 107 var v4Server = results[1]; | |
| 108 | |
| 109 if (!supportsIpV6) return v4Server; | |
| 110 | |
| 111 // Reuse the IPv4 server's port so that if [port] is 0, both servers use | |
| 112 // the same ephemeral port. | |
| 113 return bind(InternetAddress.LOOPBACK_IP_V6, v4Server.port) | |
| 114 .then((v6Server) { | |
| 115 return new HttpMultiServer([v4Server, v6Server]); | |
| 116 }); | |
| 117 }); | |
| 118 } | |
| 119 | |
| 120 Future close({bool force: false}) => | |
| 121 Future.wait(_servers.map((server) => server.close(force: force))); | |
| 122 | |
| 123 HttpConnectionsInfo connectionsInfo() { | |
|
Bob Nystrom
2014/06/04 23:58:17
Document this since it has interesting semantics.
nweiz
2014/06/05 00:36:09
Done.
| |
| 124 var info = new HttpConnectionsInfo(); | |
| 125 for (var server in _servers) { | |
| 126 var subInfo = server.connectionsInfo(); | |
| 127 info.total += subInfo.total; | |
| 128 info.active += subInfo.active; | |
| 129 info.idle += subInfo.idle; | |
| 130 info.closing += subInfo.closing; | |
| 131 } | |
| 132 return info; | |
| 133 } | |
| 134 } | |
| OLD | NEW |