Skip to content

Commit

Permalink
Add HttpMultiServer.bind utility (flutter#16)
Browse files Browse the repository at this point in the history
We have a few places where we want to allow listening on 'any' hostname
for the case where the server may be both access locally with something
like "localhost" and externally with something like the servers
hostname.
  • Loading branch information
natebosch authored Jun 4, 2019
1 parent 00a4575 commit ccc74bd
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
## 2.0.7
## 2.1.0

- Add `HttpMultiServer.bind` static which centralizes logic around common local
serving scenarios - handling a more flexible 'localhost' and listening on
'any' hostname.
- Update SDK constraints to `>=2.1.0 <3.0.0`.


## 2.0.6

* If there is a problem starting a loopback Ipv6 server, don't keep the Ipv4
Expand Down
23 changes: 23 additions & 0 deletions lib/http_multi_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,29 @@ class HttpMultiServer extends StreamView<HttpRequest> implements HttpServer {
requestClientCertificate: requestClientCertificate));
}

/// Bind an [HttpServer] with handling for special addresses 'localhost' and
/// 'any'.
///
/// For address 'localhost' behaves like [loopback]. For 'any' listens on
/// [InternetAddress.anyIPv6] which listens on all hostnames for both IPv4 and
/// IPV6. For any other address forwards directly to `HttpServer.bind` where
/// the IPvX support may vary.
///
/// See [HttpServer.bind].
static Future<HttpServer> bind(dynamic address, int port,
{int backlog = 0, bool v6Only = false, bool shared = false}) {
if (address == 'localhost') {
return HttpMultiServer.loopback(port,
backlog: backlog, v6Only: v6Only, shared: shared);
}
if (address == 'any') {
return HttpServer.bind(InternetAddress.anyIPv6, port,
backlog: backlog, v6Only: v6Only, shared: shared);
}
return HttpServer.bind(address, port,
backlog: backlog, v6Only: v6Only, shared: shared);
}

/// A helper method for initializing loopback servers.
///
/// [bind] should forward to either [HttpServer.bind] or
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: http_multi_server
version: 2.0.7-dev
version: 2.1.0

description: >-
A dart:io HttpServer wrapper that handles requests from multiple servers.
Expand Down
56 changes: 56 additions & 0 deletions test/http_multi_server_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,62 @@ void main() {
}
});
});

group("HttpMultiServer.bind", () {
test("listens on all localhost interfaces for 'localhost'", () async {
final server = await HttpMultiServer.bind("localhost", 0);
server.listen((request) {
request.response.write("got request");
request.response.close();
});

if (await supportsIPv4) {
expect(http.read("http://127.0.0.1:${server.port}/"),
completion(equals("got request")));
}

if (await supportsIPv6) {
expect(http.read("http://[::1]:${server.port}/"),
completion(equals("got request")));
}
});

test("listens on all localhost interfaces for 'any'", () async {
final server = await HttpMultiServer.bind("any", 0);
server.listen((request) {
request.response.write("got request");
request.response.close();
});

if (await supportsIPv4) {
expect(http.read("http://127.0.0.1:${server.port}/"),
completion(equals("got request")));
}

if (await supportsIPv6) {
expect(http.read("http://[::1]:${server.port}/"),
completion(equals("got request")));
}
});

test("listens on specified hostname", () async {
final server = await HttpMultiServer.bind(InternetAddress.anyIPv4, 0);
server.listen((request) {
request.response.write("got request");
request.response.close();
});

if (await supportsIPv4) {
expect(http.read("http://127.0.0.1:${server.port}/"),
completion(equals("got request")));
}

if (await supportsIPv6) {
expect(http.read("http://[::1]:${server.port}/"),
throwsA(isA<SocketException>()));
}
});
});
}

/// Makes a GET request to the root of [server] and returns the response.
Expand Down

0 comments on commit ccc74bd

Please sign in to comment.