[Http] Fix handling of ipv6 address in host header

The current implementation of _HttpHeaders._addHost does not handle
ipv6 address correctly. This patch fixes the handling and add test
case for that.

References:

- https://github.com/flutter/flutter/issues/83609#issuecomment-870356766

TEST=http_headers_test.dart has been updated with new cases.

Bug: https://github.com/flutter/flutter/issues/83609#issuecomment-870356766
Change-Id: Idc4e9bbe66d66f0d846c7a32a40854201c3b0153
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205280
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
diff --git a/sdk/lib/_http/http_headers.dart b/sdk/lib/_http/http_headers.dart
index 77b9c22..09e5748 100644
--- a/sdk/lib/_http/http_headers.dart
+++ b/sdk/lib/_http/http_headers.dart
@@ -421,8 +421,13 @@
 
   void _addHost(String name, value) {
     if (value is String) {
-      int pos = value.indexOf(":");
-      if (pos == -1) {
+      // value.indexOf will only work for ipv4, ipv6 which has multiple : in its
+      // host part needs lastIndexOf
+      int pos = value.lastIndexOf(":");
+      // According to RFC 3986, section 3.2.2, host part of ipv6 address must be
+      // enclosed by square brackets.
+      // https://serverfault.com/questions/205793/how-can-one-distinguish-the-host-and-the-port-in-an-ipv6-url
+      if (pos == -1 || value.startsWith("[") && value.endsWith("]")) {
         _host = value;
         _port = HttpClient.defaultHttpPort;
       } else {
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index 11e0f89..f2cfb6c 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -173,6 +173,40 @@
   Expect.equals(":1234", headers.value(HttpHeaders.hostHeader));
   Expect.isNull(headers.host);
   Expect.equals(1234, headers.port);
+
+  // ipv4
+  host = "123.45.67.89";
+  int port = 1234;
+  headers = new _HttpHeaders("1.1");
+  headers.add(HttpHeaders.hostHeader, "$host:$port");
+  Expect.equals("$host:$port", headers.value(HttpHeaders.hostHeader));
+  Expect.equals(host, headers.host);
+  Expect.equals(port, headers.port);
+
+  // ipv6: host+port
+  host = "[2001:db8::1]";
+  port = 1234;
+  headers = new _HttpHeaders("1.1");
+  headers.add(HttpHeaders.hostHeader, "$host:$port");
+  Expect.equals("$host:$port", headers.value(HttpHeaders.hostHeader));
+  Expect.equals(host, headers.host);
+  Expect.equals(port, headers.port);
+
+  // ipv6: host only
+  host = "[2001:db8::1]";
+  headers = new _HttpHeaders("1.1");
+  headers.add(HttpHeaders.hostHeader, "$host");
+  Expect.equals("$host", headers.value(HttpHeaders.hostHeader));
+  Expect.equals(host, headers.host);
+  Expect.equals(headers.port, HttpClient.defaultHttpPort);
+
+  // ipv6: host + invalid port
+  host = "[2001:db8::1]";
+  headers = new _HttpHeaders("1.1");
+  headers.add(HttpHeaders.hostHeader, "$host:xxx");
+  Expect.equals("$host:xxx", headers.value(HttpHeaders.hostHeader));
+  Expect.equals(host, headers.host);
+  Expect.isNull(headers.port);
 }
 
 void testTransferEncoding() {