Skip to content
Back to skills

Adblock Engine Core Patterns

ASecurity

Use when building core adblock engine architecture.

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 10, 2026
ai-agentspythongogitperformance

Works with

  • cli

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add LoopyLuci/Skills --skill adblock-engine-core-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Adblock Engine Core Patterns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Adblock Engine Core Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/loopyluci-adblock-engine-core-patterns/badge)](https://www.skillsdirectory.com/skills/loopyluci-adblock-engine-core-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: adblock-engine-core-patterns
description: "Use when building core adblock engine architecture."
version: 1.0.0
author: Hermes Agent
license: MIT
metadata:
  hermes:
    tags: [adblock, filtering, engine, architecture, networking]
    related_skills: [blocklist-manager, dns-adblock-engine, url-content-filter, pattern-matching-engine, custom-blocking-rules-compiler]
---

# Adblock Engine Core Patterns

Core architecture patterns for building adblock engines — from list parsing and rule matching through network filtering to browser integration, with focus on performance at scale.

## When to Use

- Building a new adblock engine from scratch
- Optimizing an existing adblock engine for performance
- Adding adblocking capabilities to a proxy or firewall
- Understanding how adblock engines work internally
- Implementing cross-platform adblocking

## Engine Architecture

```
List Source → Parser → Rule Index → Matcher → Filter Decision
                 ↓
           Rule Compiler
                 ↓
          Network/Content Filter
```

## Rule Formats

### AdBlock Plus (ABP) Syntax

```python
# Rule format examples:
example.com##.ad-banner      # Element hiding
||example.com/ads/*          # Network filter
@@||example.com/analytics    # Exception
/adv[\w-]+\.js/              # Regex filter
example.com$script           # Domain + type restriction
127.0.0.1 example.com        # Hosts file format

class ABPRuleParser:
    """Parse AdBlock Plus filter syntax into structured rules."""
    
    def parse(self, line):
        line = line.strip()
        if not line or line.startswith('!') or line.startswith('#'):
            return None  # Comment or empty
        
        rule = {
            'raw': line,
            'type': self._detect_type(line),
            'pattern': None,
            'domains': None,
            'options': {},
            'exception': line.startswith('@@'),
        }
        
        if rule['type'] == 'network':
            self._parse_network_rule(line, rule)
        elif rule['type'] == 'element_hiding':
            self._parse_elemhide_rule(line, rule)
        
        return rule
    
    def _detect_type(self, line):
        if '##' in line or '#@#' in line or '#?#' in line:
            return 'element_hiding'
        if line.startswith('@@') or '||' in line or '/' in line[:2]:
            return 'network'
        if not line.startswith('.') and not line.startswith('#'):
            # Hosts file or domain rule
            return 'network'
        return 'network'
    
    def _parse_network_rule(self, line, rule):
        """Parse network filter rules."""
        # Strip exception marker
        text = line[2:] if line.startswith('@@') else line
        
        # Extract options after $
        if '$' in text:
            text, options_str = text.rsplit('$', 1)
            rule['options'] = self._parse_options(options_str)
        
        # Extract domain restriction
        if 'domain=' in str(rule['options']):
            rule['domains'] = rule['options'].get('domain', '').split('|')
        
        # Parse pattern
        if text.startswith('||'):
            # Domain-based
            rule['pattern'] = text[2:]
            rule['match_type'] = 'domain'
        elif text.startswith('/') and text.endswith('/'):
            # Regex
            rule['pattern'] = text[1:-1]
            rule['match_type'] = 'regex'
        else:
            rule['pattern'] = text
            rule['match_type'] = 'pattern'
    
    def _parse_options(self, options_str):
        options = {}
        for opt in options_str.split(','):
            if '=' in opt:
                k, v = opt.split('=', 1)
                options[k] = v
            else:
                options[opt] = True
        return options
```

## Rule Indexing for Fast Matching

```python
class RuleIndex:
    """Multi-level rule index for O(1) to O(k) matching."""
    
    def __init__(self):
        # Domain-based index: domain → [rules]
        self.domain_index = {}  # e.g., {"doubleclick.net": [rule1, rule2]}
        
        # Pattern trie for prefix matching
        self.pattern_index = {}  # Starts-with patterns
        
        # Regex cache
        self.regex_cache = {}  # pattern → compiled regex
        
        # Exception index (for fast exception lookup)
        self.exception_index = {}
    
    def add_rule(self, rule):
        if rule['match_type'] == 'domain':
            self._index_domain_rule(rule)
        elif rule['match_type'] == 'regex':
            self._index_regex_rule(rule)
        else:
            self._index_pattern_rule(rule)
        
        if rule['exception']:
            self._index_exception(rule)
    
    def _index_domain_rule(self, rule):
        """Index domain-based rules."""
        domain = rule['pattern'].lstrip('.').split('/')[0]
        
        # Add to exact domain
        self.domain_index.setdefault(domain, []).append(rule)
        
        # Add to parent domains
        parts = domain.split('.')
        for i in range(1, len(parts)):
            parent = '.'.join(parts[i:])
            self.domain_index.setdefault(parent, []).append(rule)
    
    def _index_regex_rule(self, rule):
        """Pre-compile regex rules."""
        pattern = rule['pattern']
        if pattern not in self.regex_cache:
            self.regex_cache[pattern] = re.compile(pattern, re.IGNORECASE)
    
    def _index_pattern_rule(self, rule):
        """Index wildcard patterns using first token."""
        pattern = rule['pattern']
        # Use the first non-wildcard token as key
        tokens = re.split(r'[\*\^]', pattern)
        key = tokens[0] if tokens else pattern[:10]
        self.pattern_index.setdefault(key, []).append(rule)
```

## Fast Matching Engine

```python
class MatchingEngine:
    """High-performance request matching engine."""
    
    def __init__(self, rule_index):
        self.index = rule_index
    
    def match(self, url, domain=None, content_type=None):
        """Match a URL against all rules. Returns block=True/False."""
        if domain is None:
            from urllib.parse import urlparse
            domain = urlparse(url).hostname
        
        # 1. Quick domain-based check
        if domain in self.index.domain_index:
            for rule in self.index.domain_index[domain]:
                if self._match_single(url, domain, rule):
                    if rule['exception']:
                        return False  # Exception overrides
                    return True
        
        # 2. Pattern matching
        # Extract first meaningful token from URL path
        path = self._get_path_token(url)
        if path and path in self.index.pattern_index:
            for rule in self.index.pattern_index[path]:
                if self._match_single(url, domain, rule):
                    return True
        
        # 3. Regex matching (expensive, do last)
        for pattern, regex in self.index.regex_cache.items():
            if regex.search(url):
                return True
        
        return False  # Default: allow
    
    def _match_single(self, url, domain, rule):
        """Check if a single rule matches."""
        if rule['options']:
            # Check content type restrictions
            if 'script' in rule['options']:
                pass  # Would need content type from request
            # Check domain restrictions
            if rule.get('domains'):
                if not any(d in domain or domain.endswith('.' + d) 
                          for d in rule['domains']):
                    return False
        
        if rule['match_type'] == 'domain':
            return domain == rule['pattern'].split('/')[0]
        elif rule['match_type'] == 'regex':
            return self.index.regex_cache[rule['pattern']].search(url)
        elif rule['match_type'] == 'pattern':
            return self._wildcard_match(url, rule['pattern'])
    
    def _wildcard_match(self, url, pattern):
        """Fast wildcard matching (no regex)."""
        # Simple case: no wildcards
        if '*' not in pattern and '^' not in pattern:
            return pattern in url
        
        # Split on '*' and check each segment
        parts = pattern.split('*')
        pos = 0
        
        for i, part in enumerate(parts):
            if not part:
                continue
            if i == 0:
                # Must match at start
                if not url.startswith(part):
                    return False
                pos = len(part)
            elif i == len(parts) - 1:
                # Must match at end
                return url.endswith(part) and part in url[pos:]
            else:
                idx = url.find(part, pos)
                if idx == -1:
                    return False
                pos = idx + len(part)
        
        return True
```

## Network Filter Integration

```python
class AdblockNetworkFilter:
    """Integrates the adblock engine at the network level."""
    
    def __init__(self, rule_lists=None):
        self.engine = MatchingEngine(RuleIndex())
        self.rule_lists = rule_lists or []
        self._load_rules()
    
    def _load_rules(self):
        parser = ABPRuleParser()
        for list_url in self.rule_lists:
            rules = self._fetch_list(list_url)
            for rule_text in rules:
                rule = parser.parse(rule_text)
                if rule:
                    self.engine.index.add_rule(rule)
    
    def should_block_request(self, url, request_type='other', domain=None):
        """Main entry point for proxy/DNS-level filtering."""
        return self.engine.match(url, domain, request_type)
    
    def should_block_element(self, url, domain):
        """For browser-level element hiding."""
        # Element hiding rules checked separately
        pass
```

## Performance Optimization

```python
class OptimizedEngine:
    """Performance-tuned adblock engine."""
    
    # Key optimizations:
    # 1. Bloom filter for negative cache (fast reject for non-blocked URLs)
    # 2. Domain trie for O(len(domain)) lookup
    # 3. Short-circuit on common CDNs (google-analytics.com, doubleclick.net)
    # 4. LRU cache for recently checked URLs
    
    def __init__(self, bloom_filter_size=10_000_000):
        self.bloom = self._build_bloom_filter()
        self.lru_cache = lru_cache(maxsize=10000)(self._match_url)
    
    def match(self, url):
        # 1. Bloom filter: 99% of unblocked URLs rejected in O(1)
        if not self.bloom.check(url):
            return False
        
        # 2. LRU cache for recently checked URLs
        return self.lru_cache(url)
```

## Common Pitfalls

1. **Rule explosion** — 100K+ rules make matching slow; use multi-level indexing and bloom filters
2. **Regex DoS** — malicious regex rules can cause catastrophic backtracking; use timeout or reject complex regex
3. **False positives** — over-blocking legitimate content; maintain exception lists and user feedback
4. **Memory usage** — loading 10M rules can use 500MB+; compress patterns, use compact trie structures
5. **Domain parsing edge cases** — IP addresses, punycode, port numbers; use URL parser library
6. **Browser vs. network-level** — some rules only work at browser level (element hiding); separate concerns

## Verification Checklist

- [ ] Correctly blocks known ad domains (doubleclick.net, googleadservices.com)
- [ ] Correctly allows exceptions (@@ rules override)
- [ ] Performance: < 1ms per URL match with 100K rules
- [ ] Memory: < 200MB for 100K rules
- [ ] Parses all major adlist formats (ABP, hosts, uBlock Origin)
- [ ] Content type filtering works (script-only, image-only rules)
- [ ] Element hiding rules work separately from network rules

## See Also

- blocklist-manager — managing adblock lists at scale
- dns-adblock-engine — DNS-level ad blocking
- url-content-filter — URL-level filtering
- pattern-matching-engine — high-performance pattern matching
- custom-blocking-rules-compiler — compiling custom rules

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…