Skip to content

Commit 21da6fc

Browse files
committed
Add TldRuleDivisionFilter
Allow use ICANN domains only
1 parent d9a9970 commit 21da6fc

File tree

9 files changed

+105
-22
lines changed

9 files changed

+105
-22
lines changed

src/Nager.PublicSuffix.UnitTest/TldRuleExtensionsTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public void UnparseWithWildCardTest()
4646

4747
private static (TldRule[] rules1, TldRule[] rules2) ParseUnparseRules(string rulesText)
4848
{
49-
var ruleParser = new TldRuleParser();
49+
var ruleParser = new TldRuleParser(TldRuleDivisionFilter.All);
5050

5151
var rules1 = ruleParser.ParseRules(rulesText).ToArray();
5252
var rulesUnParsedText = rules1.UnparseRules();

src/Nager.PublicSuffix.UnitTest/TldRuleParserTest.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public void ParseValidData1()
1313
{
1414
var lines = new string[] { "com", "uk", "co.uk" };
1515

16-
var ruleParser = new TldRuleParser();
16+
var ruleParser = new TldRuleParser(TldRuleDivisionFilter.All);
1717
var tldRules = ruleParser.ParseRules(lines).ToList();
1818

1919
Assert.AreEqual("com", tldRules[0].Name);
@@ -26,7 +26,7 @@ public void ParseValidData2()
2626
{
2727
var lines = new string[] { "com", "//this is a example comment", "uk", "co.uk" };
2828

29-
var ruleParser = new TldRuleParser();
29+
var ruleParser = new TldRuleParser(TldRuleDivisionFilter.All);
3030
var tldRules = ruleParser.ParseRules(lines).ToList();
3131

3232
Assert.AreEqual("com", tldRules[0].Name);
@@ -50,7 +50,7 @@ public void ParseValidData3()
5050
"example.after"
5151
};
5252

53-
var ruleParser = new TldRuleParser();
53+
var ruleParser = new TldRuleParser(TldRuleDivisionFilter.All);
5454
var tldRules = ruleParser.ParseRules(lines).ToList();
5555

5656
Assert.AreEqual("example.above", tldRules[0].Name);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace Nager.PublicSuffix.Models
2+
{
3+
/// <summary>
4+
/// Specifies the type of TLD rules to include.
5+
/// </summary>
6+
public enum TldRuleDivisionFilter
7+
{
8+
/// <summary>
9+
/// Only officially recognized domains managed by ICANN.
10+
/// </summary>
11+
ICANNOnly,
12+
13+
/// <summary>
14+
/// Only privately managed domains (e.g., blogspot.com, github.io).
15+
/// </summary>
16+
PrivateOnly,
17+
18+
/// <summary>
19+
/// Both ICANN-managed and privately managed domains.
20+
/// </summary>
21+
All
22+
}
23+
}

src/Nager.PublicSuffix/Nager.PublicSuffix.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0</TargetFrameworks>
2727

28-
<Version>3.4.0</Version>
28+
<Version>3.5.0</Version>
2929
</PropertyGroup>
3030

3131
<ItemGroup>

src/Nager.PublicSuffix/README.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,34 @@ You can find the list on GitHub under [publicsuffix list repository](https://git
1717

1818
## Code Examples
1919

20-
### Analyze domain
20+
### Analyze a Domain Using a Local Public Suffix List
21+
22+
Use a local public suffix list file to analyze domains
23+
2124
```cs
2225
var ruleProvider = new LocalFileRuleProvider("public_suffix_list.dat");
2326
await ruleProvider.BuildAsync();
2427

2528
var domainParser = new DomainParser(ruleProvider);
2629

30+
var domainInfo = domainParser.Parse("sub.test.co.uk");
31+
//domainInfo.Domain = "test";
32+
//domainInfo.FullyQualifiedDomainName = "sub.test.co.uk";
33+
//domainInfo.RegistrableDomain = "test.co.uk";
34+
//domainInfo.Subdomain = "sub";
35+
//domainInfo.TopLevelDomain = "co.uk";
36+
```
37+
38+
### Analyze a Domain Using the Online Public Suffix List
39+
40+
Use a remote source to always work with the latest public suffix list
41+
42+
```cs
43+
var ruleProvider = new SimpleHttpRuleProvider();
44+
await ruleProvider.BuildAsync();
45+
46+
var domainParser = new DomainParser(ruleProvider);
47+
2748
var domainInfo = domainParser.Parse("sub.test.co.uk");
2849
//domainInfo.Domain = "test";
2950
//domainInfo.FullyQualifiedDomainName = "sub.test.co.uk";

src/Nager.PublicSuffix/RuleParsers/TldRuleParser.cs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,17 @@ namespace Nager.PublicSuffix.RuleParsers
99
/// </summary>
1010
public class TldRuleParser
1111
{
12-
private readonly char[] _lineBreak = ['\n', '\r'];
12+
private readonly char[] _newlineSeparators = ['\n', '\r'];
13+
private readonly TldRuleDivisionFilter _tldRuleDivisionFilter;
14+
15+
/// <summary>
16+
/// TldRuleParser
17+
/// </summary>
18+
/// <param name="tldRuleDivisionFilter"></param>
19+
public TldRuleParser(TldRuleDivisionFilter tldRuleDivisionFilter)
20+
{
21+
this._tldRuleDivisionFilter = tldRuleDivisionFilter;
22+
}
1323

1424
/// <summary>
1525
/// ParseRules
@@ -18,7 +28,7 @@ public class TldRuleParser
1828
/// <returns></returns>
1929
public IEnumerable<TldRule> ParseRules(string data)
2030
{
21-
var lines = data.Split(this._lineBreak);
31+
var lines = data.Split(this._newlineSeparators);
2232
return this.ParseRules(lines);
2333
}
2434

@@ -30,7 +40,7 @@ public IEnumerable<TldRule> ParseRules(string data)
3040
public IEnumerable<TldRule> ParseRules(IEnumerable<string> lines)
3141
{
3242
var items = new List<TldRule>();
33-
var division = TldRuleDivision.Unknown;
43+
var activeDivision = TldRuleDivision.Unknown;
3444

3545
foreach (var line in lines)
3646
{
@@ -46,25 +56,37 @@ public IEnumerable<TldRule> ParseRules(IEnumerable<string> lines)
4656
//Detect Division
4757
if (line.StartsWith("// ===BEGIN ICANN DOMAINS===", StringComparison.OrdinalIgnoreCase))
4858
{
49-
division = TldRuleDivision.ICANN;
59+
activeDivision = TldRuleDivision.ICANN;
5060
}
5161
else if (line.StartsWith("// ===END ICANN DOMAINS===", StringComparison.OrdinalIgnoreCase))
5262
{
53-
division = TldRuleDivision.Unknown;
63+
activeDivision = TldRuleDivision.Unknown;
5464
}
5565
else if (line.StartsWith("// ===BEGIN PRIVATE DOMAINS===", StringComparison.OrdinalIgnoreCase))
5666
{
57-
division = TldRuleDivision.Private;
67+
activeDivision = TldRuleDivision.Private;
5868
}
5969
else if (line.StartsWith("// ===END PRIVATE DOMAINS===", StringComparison.OrdinalIgnoreCase))
6070
{
61-
division = TldRuleDivision.Unknown;
71+
activeDivision = TldRuleDivision.Unknown;
6272
}
6373

6474
continue;
6575
}
6676

67-
var tldRule = new TldRule(line.Trim(), division);
77+
if (activeDivision == TldRuleDivision.Private &&
78+
this._tldRuleDivisionFilter == TldRuleDivisionFilter.ICANNOnly)
79+
{
80+
continue;
81+
}
82+
83+
if (activeDivision == TldRuleDivision.ICANN &&
84+
this._tldRuleDivisionFilter == TldRuleDivisionFilter.PrivateOnly)
85+
{
86+
continue;
87+
}
88+
89+
var tldRule = new TldRule(line.Trim(), activeDivision);
6890
items.Add(tldRule);
6991
}
7092

src/Nager.PublicSuffix/RuleProviders/CachedHttpRuleProvider.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.Extensions.Logging;
44
using Microsoft.Extensions.Logging.Abstractions;
55
using Nager.PublicSuffix.Exceptions;
6+
using Nager.PublicSuffix.Models;
67
using Nager.PublicSuffix.RuleParsers;
78
using Nager.PublicSuffix.RuleProviders.CacheProviders;
89
using System;
@@ -21,6 +22,7 @@ public class CachedHttpRuleProvider : BaseRuleProvider
2122
private readonly ILogger<CachedHttpRuleProvider> _logger;
2223
private readonly ICacheProvider _cacheProvider;
2324
private readonly HttpClient _httpClient;
25+
private readonly TldRuleDivisionFilter _tldRuleDivisionFilter;
2426

2527
/// <summary>
2628
/// Returns the cache provider
@@ -36,12 +38,14 @@ public class CachedHttpRuleProvider : BaseRuleProvider
3638
/// <param name="configuration"></param>
3739
/// <param name="cacheProvider"></param>
3840
/// <param name="httpClient"></param>
41+
/// <param name="tldRuleDivisionFilter"></param>
3942
[ActivatorUtilitiesConstructor]
4043
public CachedHttpRuleProvider(
4144
ILogger<CachedHttpRuleProvider> logger,
4245
IConfiguration configuration,
4346
ICacheProvider cacheProvider,
44-
HttpClient httpClient)
47+
HttpClient httpClient,
48+
TldRuleDivisionFilter tldRuleDivisionFilter = TldRuleDivisionFilter.All)
4549
{
4650
this._logger = logger;
4751
this._cacheProvider = cacheProvider;
@@ -54,6 +58,7 @@ public CachedHttpRuleProvider(
5458
}
5559

5660
this._dataFileUrl = url ?? throw new InvalidOperationException("_dataFileUrl must contain a non-null value");
61+
this._tldRuleDivisionFilter = tldRuleDivisionFilter;
5762
}
5863

5964
/// <summary>
@@ -65,16 +70,18 @@ public CachedHttpRuleProvider(
6570
/// <param name="httpClient"></param>
6671
/// <param name="configuration"></param>
6772
/// <param name="logger"></param>
73+
/// <param name="tldRuleDivisionFilter"></param>
6874
public CachedHttpRuleProvider(
6975
ICacheProvider cacheProvider,
7076
HttpClient httpClient,
7177
IConfiguration? configuration = default,
72-
ILogger<CachedHttpRuleProvider>? logger = default
73-
)
78+
ILogger<CachedHttpRuleProvider>? logger = default,
79+
TldRuleDivisionFilter tldRuleDivisionFilter = TldRuleDivisionFilter.All)
7480
{
7581
this._cacheProvider = cacheProvider;
7682
this._httpClient = httpClient;
7783
this._logger = logger ?? new NullLogger<CachedHttpRuleProvider>();
84+
this._tldRuleDivisionFilter = tldRuleDivisionFilter;
7885

7986
var url = "https://publicsuffix.org/list/public_suffix_list.dat";
8087
if (configuration != default)
@@ -122,7 +129,7 @@ public override async Task<bool> BuildAsync(
122129
return false;
123130
}
124131

125-
var ruleParser = new TldRuleParser();
132+
var ruleParser = new TldRuleParser(this._tldRuleDivisionFilter);
126133
var rules = ruleParser.ParseRules(ruleData!);
127134

128135
base.CreateDomainDataStructure(rules);

src/Nager.PublicSuffix/RuleProviders/LocalFileRuleProvider.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@ namespace Nager.PublicSuffix.RuleProviders
1313
public class LocalFileRuleProvider : BaseRuleProvider
1414
{
1515
private readonly string _filePath;
16+
private readonly TldRuleDivisionFilter _tldRuleDivisionFilter;
1617

1718
/// <summary>
1819
/// LocalFile RuleProvider
1920
/// </summary>
2021
/// <param name="filePath"></param>
21-
public LocalFileRuleProvider(string filePath)
22+
/// <param name="tldRuleDivisionFilter"></param>
23+
public LocalFileRuleProvider(
24+
string filePath,
25+
TldRuleDivisionFilter tldRuleDivisionFilter = TldRuleDivisionFilter.All)
2226
{
2327
this._filePath = filePath;
28+
this._tldRuleDivisionFilter = tldRuleDivisionFilter;
2429
}
2530

2631
/// <inheritdoc/>
@@ -30,7 +35,7 @@ public override async Task<bool> BuildAsync(
3035
{
3136
var ruleData = await this.LoadFromFile().ConfigureAwait(false);
3237

33-
var ruleParser = new TldRuleParser();
38+
var ruleParser = new TldRuleParser(this._tldRuleDivisionFilter);
3439
var rules = ruleParser.ParseRules(ruleData);
3540

3641
var domainDataStructure = new DomainDataStructure("*", new TldRule("*"));

src/Nager.PublicSuffix/RuleProviders/SimpleHttpRuleProvider.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.Extensions.Logging;
33
using Microsoft.Extensions.Logging.Abstractions;
44
using Nager.PublicSuffix.Exceptions;
5+
using Nager.PublicSuffix.Models;
56
using Nager.PublicSuffix.RuleParsers;
67
using System;
78
using System.Net.Http;
@@ -20,6 +21,7 @@ public class SimpleHttpRuleProvider : BaseRuleProvider, IDisposable
2021
private readonly ILogger<SimpleHttpRuleProvider> _logger;
2122
private readonly HttpClient _httpClient;
2223
private readonly bool _disposeHttpClient;
24+
private readonly TldRuleDivisionFilter _tldRuleDivisionFilter;
2325

2426
/// <summary>
2527
/// Simple Http RuleProvider<br/>
@@ -29,15 +31,18 @@ public class SimpleHttpRuleProvider : BaseRuleProvider, IDisposable
2931
/// <param name="configuration"></param>
3032
/// <param name="httpClient"></param>
3133
/// <param name="logger"></param>
34+
/// <param name="tldRuleDivisionFilter"></param>
3235
public SimpleHttpRuleProvider(
3336
IConfiguration? configuration = null,
3437
HttpClient? httpClient = null,
35-
ILogger<SimpleHttpRuleProvider>? logger = null)
38+
ILogger<SimpleHttpRuleProvider>? logger = null,
39+
TldRuleDivisionFilter tldRuleDivisionFilter = TldRuleDivisionFilter.All)
3640
{
3741
this._logger = logger ?? new NullLogger<SimpleHttpRuleProvider>();
3842

3943
this._disposeHttpClient = httpClient == null;
4044
this._httpClient = httpClient ?? new HttpClient();
45+
this._tldRuleDivisionFilter = tldRuleDivisionFilter;
4146

4247
var url = configuration != null ? configuration["Nager:PublicSuffix:DataUrl"] : string.Empty;
4348
if (string.IsNullOrEmpty(url))
@@ -99,7 +104,7 @@ public override async Task<bool> BuildAsync(
99104
return false;
100105
}
101106

102-
var ruleParser = new TldRuleParser();
107+
var ruleParser = new TldRuleParser(this._tldRuleDivisionFilter);
103108
var rules = ruleParser.ParseRules(ruleData);
104109

105110
base.CreateDomainDataStructure(rules);

0 commit comments

Comments
 (0)