From 76299bdd80a67a21abaca798d4289c63c625d3db Mon Sep 17 00:00:00 2001 From: "LamTrinh.Dev" Date: Thu, 30 Apr 2026 21:30:12 +0700 Subject: [PATCH] perf(proxy): optimize subdomain checking by building candidates incrementally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace O(n²) strings.Join in loop with O(n) incremental string building. For domains with many subdomains (e.g., a.b.c.d.e.com), this reduces string operations from n*(n+1)/2 to n. Before: strings.Join(parts[i:], ".") in loop creates n+(n-1)+...+1 operations After: Build strings incrementally by prepending parts: n operations --- proxy/filter/blocklists.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/proxy/filter/blocklists.go b/proxy/filter/blocklists.go index b6a97fed..4df68664 100644 --- a/proxy/filter/blocklists.go +++ b/proxy/filter/blocklists.go @@ -50,8 +50,20 @@ func (f *DomainFilter) filterBlocklists(reqCtx *requestcontext.RequestContext, d if reqCtx.PrivacySettings[SUBDOMAINS_RULE] == RULE_BLOCK { // iterate over all subdomains parts := strings.Split(fqdn, ".") - for i := range len(parts) - 1 { - candidate := strings.Join(parts[i:], ".") + var candidate string + for i := len(parts) - 1; i >= 0; i-- { + // Build candidate incrementally by prepending current part + if i == len(parts)-1 { + candidate = parts[i] + } else { + candidate = parts[i] + "." + candidate + } + + // Skip the full domain as it was already checked above + if i == 0 { + continue + } + // now, check if candidate domain is part of any blocklist entry blocklisted, err = f.Cache.GetBlocklistEntry(context.Background(), blocklistId, candidate) if err != nil {