| 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/multi_headers.dart'; | |
| 11 import 'src/utils.dart'; | |
| 12 | |
| 13 /// An implementation of `dart:io`'s [HttpServer] that wraps multiple servers | |
| 14 /// and forwards methods to all of them. | |
| 15 /// | |
| 16 /// This is useful for serving the same application on multiple network | |
| 17 /// 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 | |
| 19 /// using [HttpMultiServer.loopback]. | |
| 20 class HttpMultiServer extends StreamView<HttpRequest> implements HttpServer { | |
| 21 /// The wrapped servers. | |
| 22 final Set<HttpServer> _servers; | |
| 23 | |
| 24 /// Returns the default value of the `Server` header for all responses | |
| 25 /// generated by each server. | |
| 26 /// | |
| 27 /// If the wrapped servers have different default values, it's not defined | |
| 28 /// which value is returned. | |
| 29 String get serverHeader => _servers.first.serverHeader; | |
| 30 set serverHeader(String value) { | |
| 31 for (var server in _servers) { | |
| 32 server.serverHeader = value; | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 /// Returns the default set of headers added to all response objects. | |
| 37 /// | |
| 38 /// If the wrapped servers have different default headers, it's not defined | |
| 39 /// which header is returned for accessor methods. | |
| 40 final HttpHeaders defaultResponseHeaders; | |
| 41 | |
| 42 Duration get idleTimeout => _servers.first.idleTimeout; | |
| 43 set idleTimeout(Duration value) { | |
| 44 for (var server in _servers) { | |
| 45 server.idleTimeout = value; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 bool get autoCompress => _servers.first.autoCompress; | |
| 50 set autoCompress(bool value) { | |
| 51 for (var server in _servers) { | |
| 52 server.autoCompress = value; | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 /// Returns the port that one of the wrapped servers is listening on. | |
| 57 /// | |
| 58 /// If the wrapped servers are listening on different ports, it's not defined | |
| 59 /// which port is returned. | |
| 60 int get port => _servers.first.port; | |
| 61 | |
| 62 /// Returns the address that one of the wrapped servers is listening on. | |
| 63 /// | |
| 64 /// If the wrapped servers are listening on different addresses, it's not | |
| 65 /// defined which address is returned. | |
| 66 InternetAddress get address => _servers.first.address; | |
| 67 | |
| 68 set sessionTimeout(int value) { | |
| 69 for (var server in _servers) { | |
| 70 server.sessionTimeout = value; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 /// Creates an [HttpMultiServer] wrapping [servers]. | |
| 75 /// | |
| 76 /// All [servers] should have the same configuration and none should be | |
| 77 /// listened to when this is called. | |
| 78 HttpMultiServer(Iterable<HttpServer> servers) | |
| 79 : _servers = servers.toSet(), | |
| 80 defaultResponseHeaders = new MultiHeaders( | |
| 81 servers.map((server) => server.defaultResponseHeaders)), | |
| 82 super(mergeStreams(servers)); | |
| 83 | |
| 84 /// Creates an [HttpServer] listening on all available loopback addresses for | |
| 85 /// this computer. | |
| 86 /// | |
| 87 /// If this computer supports both IPv4 and IPv6, this returns an | |
| 88 /// [HttpMultiServer] listening to [port] on both loopback addresses. | |
| 89 /// Otherwise, it returns a normal [HttpServer] listening only on the IPv4 | |
| 90 /// address. | |
| 91 /// | |
| 92 /// If [port] is 0, the same ephemeral port is used for both the IPv4 and IPv6 | |
| 93 /// addresses. | |
| 94 static Future<HttpServer> loopback(int port, {int backlog}) { | |
| 95 if (backlog == null) backlog = 0; | |
| 96 | |
| 97 return _loopback(port, (address, port) => | |
| 98 HttpServer.bind(address, port, backlog: backlog)); | |
| 99 } | |
| 100 | |
| 101 /// Like [loopback], but supports HTTPS requests. | |
| 102 /// | |
| 103 /// The certificate with nickname or distinguished name (DN) [certificateName] | |
| 104 /// is looked up in the certificate database, and is used as the server | |
| 105 /// certificate. If [requestClientCertificate] is true, the server will | |
| 106 /// request clients to authenticate with a client certificate. | |
| 107 static Future<HttpServer> loopbackSecure(int port, {int backlog, | |
| 108 String certificateName, bool requestClientCertificate: false}) { | |
| 109 if (backlog == null) backlog = 0; | |
| 110 | |
| 111 return _loopback(port, (address, port) => | |
| 112 HttpServer.bindSecure(address, port, backlog: backlog, | |
| 113 certificateName: certificateName, | |
| 114 requestClientCertificate: requestClientCertificate)); | |
| 115 } | |
| 116 | |
| 117 /// A helper method for initializing loopback servers. | |
| 118 /// | |
| 119 /// [bind] should forward to either [HttpServer.bind] or | |
| 120 /// [HttpServer.bindSecure]. | |
| 121 static Future<HttpServer> _loopback(int port, | |
| 122 Future<HttpServer> bind(InternetAddress address, int port)) { | |
| 123 return Future.wait([ | |
| 124 supportsIpV6, | |
| 125 bind(InternetAddress.LOOPBACK_IP_V4, port) | |
| 126 ]).then((results) { | |
| 127 var supportsIpV6 = results[0]; | |
| 128 var v4Server = results[1]; | |
| 129 | |
| 130 if (!supportsIpV6) return v4Server; | |
| 131 | |
| 132 // Reuse the IPv4 server's port so that if [port] is 0, both servers use | |
| 133 // the same ephemeral port. | |
| 134 return bind(InternetAddress.LOOPBACK_IP_V6, v4Server.port) | |
| 135 .then((v6Server) { | |
| 136 return new HttpMultiServer([v4Server, v6Server]); | |
| 137 }); | |
| 138 }); | |
| 139 } | |
| 140 | |
| 141 Future close({bool force: false}) => | |
| 142 Future.wait(_servers.map((server) => server.close(force: force))); | |
| 143 | |
| 144 /// Returns an HttpConnectionsInfo object summarizing the total number of | |
| 145 /// current connections handled by all the servers. | |
| 146 HttpConnectionsInfo connectionsInfo() { | |
| 147 var info = new HttpConnectionsInfo(); | |
| 148 for (var server in _servers) { | |
| 149 var subInfo = server.connectionsInfo(); | |
| 150 info.total += subInfo.total; | |
| 151 info.active += subInfo.active; | |
| 152 info.idle += subInfo.idle; | |
| 153 info.closing += subInfo.closing; | |
| 154 } | |
| 155 return info; | |
| 156 } | |
| 157 } | |
| OLD | NEW |