Instruction file imported from JakeChampion/trafficserver (
.github/instructions/HRW.instructions.md). Copyright stays with the author.
Header Rewrite Plugin and HRW4U Transpiler
Overview
Two closely related components that must be kept in sync:
- header_rewrite plugin (
plugins/header_rewrite/) - ATS plugin for modifying HTTP headers - hrw4u transpiler (
tools/hrw4u/) - DSL compiler for generating header_rewrite configurations
Critical Requirement: Feature Synchronization
Features added to either component may require corresponding changes in the other.
When to Update Both
- New operator in header_rewrite → Add syntax and code generation in hrw4u
- New condition in header_rewrite → Add parsing and symbols in hrw4u
- New variable/resource in header_rewrite → Update hrw4u symbol tables and types
- New hook in header_rewrite → Add hook syntax in hrw4u
- New hrw4u syntax → Ensure correct header_rewrite config generation
Bidirectional Compilation
Both directions must work:
- hrw4u (forward): HRW4U source → header_rewrite config
- u4wrh (reverse): header_rewrite config → HRW4U source
Round-trip test: hrw4u example.hrw4u | u4wrh should produce equivalent output.
Header Rewrite Plugin
Architecture
Core files:
parser.cc/h- Configuration syntax parserfactory.cc/h- Factory for operators and conditionsoperators.cc/h- Header manipulation operationsconditions.cc/h- Conditional logicresources.cc/h- Available variables (headers, IPs, etc.)statement.cc/h- Rule statement abstractionruleset.cc/h- Rule collection and executionmatcher.cc/h- Pattern matchingvalue.cc/h- Value extraction and manipulation
Adding Features
New operator:
- Define class in
operators.h, implement inoperators.cc - Register in
factory.cc - Update hrw4u:
tables.py(forward mapping tables),visitor.py(forward compiler - HRW4UVisitor), andgenerators.py(reverse-resolution tables used by u4wrh)
New condition:
- Define class in
conditions.h, implement inconditions.cc - Register in
factory.cc - Update hrw4u:
visitor.pyfor parsing,tables.pyfor symbol maps
New resource/variable:
- Define in
resources.h, implement inresources.cc - Update hrw4u:
types.pyfor type system,tables.py(OPERATOR_MAP/CONDITION_MAP/etc.) for symbol tables,symbols.pyfor resolver wiring, andgenerators.pyfor reverse mappings
HRW4U Transpiler
Purpose
Provides readable DSL syntax that compiles to header_rewrite configuration.
Requirements: Python 3.11+, ANTLR4
Project Structure
tools/hrw4u/
├── src/ # Python source
│ ├── common.py # Shared utilities
│ ├── types.py # Type system
│ ├── symbols.py # Symbol resolution
│ ├── hrw_symbols.py # Header rewrite symbols
│ ├── tables.py # Symbol/type tables
│ ├── visitor.py # Forward compiler (HRW4UVisitor - hrw4u script)
│ ├── hrw_visitor.py # Reverse compiler (HRWInverseVisitor - u4wrh script)
│ ├── generators.py # Reverse-resolution table generation
│ ├── validation.py # Semantic validation
│ └── lsp/ # LSP server
├── scripts/ # CLI tools
│ ├── hrw4u # Forward compiler (hrw4u → HRW config)
│ ├── u4wrh # Reverse compiler (HRW config → hrw4u)
│ └── hrw4u-lsp # LSP server
├── grammar/ # ANTLR4 grammars
└── tests/ # Test suite
Key Modules
Type System (types.py):
- HRW4U type hierarchy
- Variable types (string, int, bool, IP, etc.)
- Operator signatures
- Type checking and inference
Symbol Resolution (symbols.py, hrw_symbols.py, tables.py):
- Symbol tables for variables, operators, functions
- Scope management
- Built-in symbols for header_rewrite resources
Reverse-Resolution Tables (generators.py):
- Generates derived tables and reverse mappings from primary forward tables
- Used by u4wrh (reverse compiler) to map HRW config back to hrw4u syntax
- Eliminates duplication by maintaining single source of truth in forward tables
Visitors:
visitor.py(HRW4UVisitor) - Forward compilation: hrw4u DSL → header_rewrite confighrw_visitor.py(HRWInverseVisitor) - Reverse compilation: header_rewrite config → hrw4u DSLkg_visitor.py(KnowledgeGraphVisitor) - Extracts structured graph data for analysis/visualization (used byhrw4u-kgscript, rarely modified)
Adding Features
New operator:
- Update grammar if new syntax needed
- Add symbol definition in
hrw_symbols.py - Add type signature in
types.py - Update forward compiler in
visitor.py(HRW4UVisitor) to handle new operator - Update
generators.pyto generate reverse mappings for u4wrh - Update reverse compiler in
hrw_visitor.py(HRWInverseVisitor) if special handling needed - Add tests in
tests/test_ops.pyandtests/test_ops_reverse.py - Update corresponding header_rewrite plugin code
New condition:
- Update grammar if needed
- Add symbol definition in
hrw_symbols.pyand type info intypes.py - Update forward compiler in
visitor.py(HRW4UVisitor) - Update
generators.pyfor reverse mappings - Update reverse compiler in
hrw_visitor.py(HRWInverseVisitor) if needed - Add tests
- Update header_rewrite plugin
New variable:
- Add to symbol tables (
tables.py,hrw_symbols.py) - Add type definition (
types.py) - Update forward compiler in
visitor.py(HRW4UVisitor) for property access - Update
generators.pyfor reverse mappings - Add tests
- Ensure header_rewrite supports it
Code Style
Python (3.11+):
- 4-space indentation (never tabs)
- Type hints on all functions
- Dataclasses for structured data
- Modern Python features (match/case, walrus operator)
C++ (header_rewrite):
- Follow ATS C++20 standards
- CamelCase classes, snake_case functions/variables
- 2-space indentation
- Empty line after declarations
Feature Addition Example
Hypothetical example to illustrate the workflow:
Adding a has-prefix operator (this operator does not exist):
-
header_rewrite plugin:
// operators.h class OperatorHasPrefix : public Operator { void exec(const Resources &res) override; }; // operators.cc - implement exec() // factory.cc - register operator -
hrw4u transpiler:
# hrw_symbols.py OPERATORS = { 'has-prefix': OperatorSymbol( name='has-prefix', params=['target', 'prefix'], return_type=BoolType() ), } # generators.py def generate_has_prefix_op(target, prefix): return f'has-prefix {target} {prefix}' # tests/test_ops.py def test_has_prefix(): # Test forward compilation # tests/test_ops_reverse.py def test_has_prefix_reverse(): # Test reverse compilation -
Verify round-trip:
echo 'REMAP { if req.Host has-prefix "www." { } }' | hrw4u | u4wrh
Common Pitfalls
- Forgetting to update both components - Changes often need coordination
- Breaking round-trip - Always test
hrw4u | u4wrhround-trip - Symbol table drift - Keep hrw4u symbols synced with plugin capabilities
- Type mismatches - Ensure type system matches plugin runtime behavior
- Missing tests - Add tests for both forward and reverse compilation
Documentation
- User docs:
doc/admin-guide/plugins/header_rewrite.en.html - Plugin README:
plugins/header_rewrite/README - HRW4U README:
tools/hrw4u/README.md - LSP README:
tools/hrw4u/LSP_README.md