fix h2 IPv6 parse

This commit is contained in:
wanghongenpin
2026-03-11 21:04:49 +08:00
parent 42842236ea
commit 25fec1f5e0
3 changed files with 156 additions and 4 deletions

View File

@@ -451,10 +451,24 @@ class Http2RequestDecoder extends Http2Codec<HttpRequest> {
// 解析 authority提取主机和端口
String host = authority;
int port = (scheme == 'https' ? 443 : 80);
if (authority.contains(':')) {
var parts = authority.split(':');
host = parts[0];
port = int.tryParse(parts[1]) ?? (scheme == 'https' ? 443 : 80);
if (authority.startsWith("[")) {
int closeBracketIndex = authority.indexOf(']');
if (closeBracketIndex != -1) {
host = authority.substring(0, closeBracketIndex + 1);
if (authority.length > closeBracketIndex + 1 && authority[closeBracketIndex + 1] == ':') {
port = int.tryParse(authority.substring(closeBracketIndex + 2)) ?? port;
}
}
} else {
int lastColonIndex = authority.lastIndexOf(':');
if (lastColonIndex != -1) {
var p = int.tryParse(authority.substring(lastColonIndex + 1));
if (p != null) {
host = authority.substring(0, lastColonIndex);
port = p;
}
}
}
httpRequest.hostAndPort = HostAndPort("$scheme://", host, port);
}

View File

@@ -228,6 +228,7 @@ class HttpRequest extends HttpMessage {
_requestUri ??= Uri.parse(requestUrl);
return _requestUri;
} catch (e) {
logger.w('parse uri error $requestUrl ${hostAndPort?.scheme} ${hostAndPort?.host}: $e');
return null;
}
}

137
test/temp_ipv6_test.dart Normal file
View File

@@ -0,0 +1,137 @@
import 'package:test/test.dart';
void main() {
test('Parsed IPv6 authority correctly', () {
var authority = "[240c:409f:1000::4:0:a5]";
var scheme = "https";
String host = authority;
int port = (scheme == 'https' ? 443 : 80);
if (authority.startsWith("[")) {
int closeBracketIndex = authority.indexOf(']');
if (closeBracketIndex != -1) {
host = authority.substring(0, closeBracketIndex + 1);
if (authority.length > closeBracketIndex + 1 && authority[closeBracketIndex + 1] == ':') {
port = int.tryParse(authority.substring(closeBracketIndex + 2)) ?? port;
}
}
} else {
int lastColonIndex = authority.lastIndexOf(':');
if (lastColonIndex != -1) {
var p = int.tryParse(authority.substring(lastColonIndex + 1));
if (p != null) {
host = authority.substring(0, lastColonIndex);
port = p;
}
}
}
expect(host, "[240c:409f:1000::4:0:a5]");
expect(port, 443);
});
test('Parsed IPv6 authority with port correctly', () {
var authority = "[240c:409f:1000::4:0:a5]:8080";
var scheme = "https";
String host = authority;
int port = (scheme == 'https' ? 443 : 80);
if (authority.startsWith("[")) {
int closeBracketIndex = authority.indexOf(']');
if (closeBracketIndex != -1) {
host = authority.substring(0, closeBracketIndex + 1);
if (authority.length > closeBracketIndex + 1 && authority[closeBracketIndex + 1] == ':') {
port = int.tryParse(authority.substring(closeBracketIndex + 2)) ?? port;
}
}
} else {
int lastColonIndex = authority.lastIndexOf(':');
if (lastColonIndex != -1) {
var p = int.tryParse(authority.substring(lastColonIndex + 1));
if (p != null) {
host = authority.substring(0, lastColonIndex);
port = p;
}
}
}
expect(host, "[240c:409f:1000::4:0:a5]");
expect(port, 8080);
});
test('Parsed IPv6 authority broken', () {
// case from log: [240c
// Though log says host=[240c, authority was [240c:409f:1000::4:0:a5]
// This testcase is checking if the logic handles incomplete ipv6 gracefully?
// If authority is literally "[240c", it has start [ but no ].
var authority = "[240c";
var scheme = "https";
String host = authority;
int port = (scheme == 'https' ? 443 : 80);
if (authority.startsWith("[")) {
int closeBracketIndex = authority.indexOf(']');
if (closeBracketIndex != -1) {
host = authority.substring(0, closeBracketIndex + 1);
if (authority.length > closeBracketIndex + 1 && authority[closeBracketIndex + 1] == ':') {
port = int.tryParse(authority.substring(closeBracketIndex + 2)) ?? port;
}
}
} else {
// ...
}
// Logic says: if start with [ but no ], host remains authority.
expect(host, "[240c");
});
test('Parsed IPv4 authority correctly', () {
var authority = "192.168.1.1:8080";
var scheme = "http";
String host = authority;
int port = (scheme == 'https' ? 443 : 80);
if (authority.startsWith("[")) {
// ...
} else {
int lastColonIndex = authority.lastIndexOf(':');
if (lastColonIndex != -1) {
var p = int.tryParse(authority.substring(lastColonIndex + 1));
if (p != null) {
host = authority.substring(0, lastColonIndex);
port = p;
}
}
}
expect(host, "192.168.1.1");
expect(port, 8080);
});
test('Parsed simple hostname correctly', () {
var authority = "example.com";
var scheme = "https";
String host = authority;
int port = (scheme == 'https' ? 443 : 80);
if (authority.startsWith("[")) {
// ...
} else {
int lastColonIndex = authority.lastIndexOf(':');
if (lastColonIndex != -1) {
var p = int.tryParse(authority.substring(lastColonIndex + 1));
if (p != null) {
host = authority.substring(0, lastColonIndex);
port = p;
}
}
}
expect(host, "example.com");
expect(port, 443);
});
}