Skip to content

Commit a108849

Browse files
awelburngmarz
authored andcommitted
Backport of #2351: Sniffing support for IPv6
Add SniffResponseTesting to expose SniffResponse.AddressRe for unit testing Add example IPv4/IPv6 addresses to check AddressRe matches fix #2350 rename AddressRe to AddressRegex expose SniffResponse's AddressRegex reduce visibility of nodes property Add internal ctor so that only Elasticsearch.Net can instantiate it
1 parent d212539 commit a108849

File tree

4 files changed

+79
-34
lines changed

4 files changed

+79
-34
lines changed

src/Elasticsearch.Net/Transport/Sniff/SniffResponse.cs

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,45 @@
55

66
namespace Elasticsearch.Net
77
{
8-
internal class SniffResponse
8+
public class SniffResponse
99
{
10+
//internal ctor - so that only Elasticsearch.Net can instantiate it
11+
internal SniffResponse()
12+
{
13+
}
1014

11-
private static Regex AddressRe { get; } = new Regex(@"^((?<fqdn>[^/]+)/)?(?<ip>[^:]+):(?<port>\d+)$");
15+
public static Regex AddressRegex { get; } = new Regex(@"^((?<fqdn>[^/]+)/)?(?<ip>[^:]+|\[[\da-fA-F:\.]+\]):(?<port>\d+)$");
1216

1317
public string cluster_name { get; set; }
14-
public Dictionary<string, NodeInfo> nodes { get; set; }
18+
internal Dictionary<string, NodeInfo> nodes { get; set; }
1519

1620
public IEnumerable<Node> ToNodes(bool forceHttp = false)
1721
{
18-
foreach (var kv in nodes.Where(n => n.Value.HttpEnabled))
22+
foreach (var kv in nodes.Where(n => n.Value.HttpEnabled))
1923
{
2024
yield return new Node(this.ParseToUri(kv.Value.http?.bound_address.FirstOrDefault(), forceHttp))
2125
{
2226
Name = kv.Value.name,
2327
Id = kv.Key,
2428
MasterEligible = kv.Value.MasterEligible,
25-
HoldsData = kv.Value.HoldsData,
26-
};
29+
HoldsData = kv.Value.HoldsData,
30+
};
2731
}
2832
}
2933

30-
private Uri ParseToUri(string boundAddress, bool forceHttp)
31-
{
32-
if (boundAddress.IsNullOrEmpty()) return null;
33-
var suffix = forceHttp ? "s" : string.Empty;
34-
var match = AddressRe.Match(boundAddress);
35-
if (!match.Success) throw new Exception($"Can not parse bound_address: {boundAddress} to Uri");
36-
37-
var fqdn = match.Groups["fqdn"].Value?.Trim();
38-
var ip = match.Groups["ip"].Value?.Trim();
39-
var port = match.Groups["port"].Value?.Trim();
40-
var host = !fqdn.IsNullOrEmpty() ? fqdn : ip;
41-
42-
return new Uri($"http{suffix}://{host}:{port}");
34+
private Uri ParseToUri(string boundAddress, bool forceHttp)
35+
{
36+
if (boundAddress.IsNullOrEmpty()) return null;
37+
var suffix = forceHttp ? "s" : string.Empty;
38+
var match = AddressRegex.Match(boundAddress);
39+
if (!match.Success) throw new Exception($"Can not parse bound_address: {boundAddress} to Uri");
40+
41+
var fqdn = match.Groups["fqdn"].Value?.Trim();
42+
var ip = match.Groups["ip"].Value?.Trim();
43+
var port = match.Groups["port"].Value?.Trim();
44+
var host = !fqdn.IsNullOrEmpty() ? fqdn : ip;
45+
46+
return new Uri($"http{suffix}://{host}:{port}");
4347
}
4448
}
4549

@@ -55,21 +59,21 @@ internal class NodeInfo
5559
public NodeInfoHttp http { get; set; }
5660
public IDictionary<string, string> settings { get; set; }
5761

58-
internal bool MasterEligible => this.roles?.Contains("master") ?? false;
59-
internal bool HoldsData => this.roles?.Contains("data") ?? false;
60-
internal bool HttpEnabled
61-
{
62-
get
63-
{
64-
if (this.settings != null && this.settings.ContainsKey("http.enabled"))
65-
return Convert.ToBoolean(this.settings["http.enabled"]);
66-
return http != null;
67-
}
68-
}
62+
internal bool MasterEligible => this.roles?.Contains("master") ?? false;
63+
internal bool HoldsData => this.roles?.Contains("data") ?? false;
64+
internal bool HttpEnabled
65+
{
66+
get
67+
{
68+
if (this.settings != null && this.settings.ContainsKey("http.enabled"))
69+
return Convert.ToBoolean(this.settings["http.enabled"]);
70+
return http != null;
71+
}
72+
}
6973
}
7074

71-
internal class NodeInfoHttp
72-
{
73-
public IList<string> bound_address { get; set; }
75+
internal class NodeInfoHttp
76+
{
77+
public IList<string> bound_address { get; set; }
7478
}
7579
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using FluentAssertions;
2+
using Tests.Framework;
3+
4+
namespace Tests.ClientConcepts.ConnectionPooling.Sniffing
5+
{
6+
public class AddressParsing
7+
{
8+
[U]
9+
public void IsMatched()
10+
{
11+
//based on examples from http://www.ietf.org/rfc/rfc2732.txt
12+
var testcases = new[,]
13+
{
14+
{"[::1]:9200", "[::1]", "9200"},
15+
{"192.168.2.1:231", "192.168.2.1", "231"},
16+
{"[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80", "[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]", "80"},
17+
{"[1080:0:0:0:8:800:200C:417A]:1234", "[1080:0:0:0:8:800:200C:417A]", "1234"},
18+
{"[3ffe:2a00:100:7031::1]:1", "[3ffe:2a00:100:7031::1]", "1"},
19+
{"[1080::8:800:200C:417A]:123", "[1080::8:800:200C:417A]", "123"},
20+
{"[::192.9.5.5]:12", "[::192.9.5.5]", "12"},
21+
{"[::FFFF:129.144.52.38]:80", "[::FFFF:129.144.52.38]", "80"},
22+
{"[2010:836B:4179::836B:4179]:34533", "[2010:836B:4179::836B:4179]", "34533"}
23+
};
24+
25+
for (var i = 0; i < testcases.GetLength(0); i++)
26+
{
27+
var address = testcases[i, 0];
28+
var ip = testcases[i, 1];
29+
var port = testcases[i, 2];
30+
31+
var match = Elasticsearch.Net.SniffResponse.AddressRegex.Match(address);
32+
33+
match.Success.Should().BeTrue();
34+
35+
match.Groups["ip"].Value.ShouldBeEquivalentTo(ip);
36+
match.Groups["port"].Value.ShouldBeEquivalentTo(port);
37+
}
38+
}
39+
}
40+
}

src/Tests/Framework/VirtualClustering/VirtualClusterConnection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public override ElasticsearchResponse<TReturn> Request<TReturn>(RequestData requ
5353
this._cluster.SniffingRules,
5454
requestData.RequestTimeout,
5555
(r) => this.UpdateCluster(r.NewClusterState),
56-
(r) => SniffResponse.Create(this._cluster.Nodes, this._cluster.SniffShouldReturnFqnd)
56+
(r) => MockResponses.SniffResponse.Create(this._cluster.Nodes, this._cluster.SniffShouldReturnFqnd)
5757
);
5858
}
5959
if (IsPingRequest(requestData))

src/Tests/Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@
219219
<Compile Include="Cat\CatThreadPool\CatThreadpoolApiTests.cs" />
220220
<Compile Include="Cat\CatThreadPool\CatThreadPoolUrlTests.cs" />
221221
<Compile Include="ClientConcepts\ConnectionPooling\Dispose\ResponseBuilderDisposeTests.cs" />
222+
<Compile Include="ClientConcepts\ConnectionPooling\Sniffing\AddressParsing.doc.cs" />
222223
<Compile Include="Cluster\TaskManagement\GetTask\GetTaskApiTests.cs" />
223224
<Compile Include="Cluster\TaskManagement\GetTask\GetTaskUrlTests.cs" />
224225
<Compile Include="Document\Multiple\Bulk\BulkInvalidVersionApiTests.cs" />

0 commit comments

Comments
 (0)