trafficserver
apache/trafficserver/.github/copilot-instructions.md
Apache Traffic Server (ATS) is a high-performance HTTP/HTTPS caching proxy server written in C++20. It processes large-scale web traffic using an event-driven, multi-threaded architecture with a sophisticated plugin system. Key Facts: - ~500K lines of C++20 code (strict - no C++23) - Event-driven architecture using Continuation callbacks - Handles HTTP/1.1, HTTP/2, HTTP/3 (QUIC) - Supports TLS termination and caching - Extensible via C/C++ plugins Some of these rules are enforced automatically by CI (via clang-format and clang-tidy); others are recommended…
What's in it
- Apache Traffic Server - GitHub Copilot Instructions
- Repository Overview
- Code Style Requirements
- C++ Style Guidelines
- Comments and Documentation
- Python Style
- License Headers
- Architecture Patterns
- Event-Driven Model (CRITICAL)
- HTTP State Machine
- Threading Model
- Debug Logging Pattern
- Project Structure (Key Paths)
- Key Files to Understand
- Common Patterns
- Finding Examples
- Code Organization
- Async Operation Pattern
- Error Handling
- Testing Approach
- AuTest Process Lifetime in Code Reviews
- Configuration
- Adding New Configuration Records
- What to Avoid
- Common Mistakes
- Additional Resources
# Apache Traffic Server - GitHub Copilot Instructions
## Repository Overview
Apache Traffic Server (ATS) is a high-performance HTTP/HTTPS caching proxy server written in C++20. It processes large-scale web traffic using an event-driven, multi-threaded architecture with a sophisticated plugin system.
**Key Facts:**
- ~500K lines of C++20 code (strict - no C++23)
- Event-driven architecture using Continuation callbacks
- Handles HTTP/1.1, HTTP/2, HTTP/3 (QUIC)
- Supports TLS termination and caching
- Extensible via C/C++ plugins
## Code Style Requirements
### C++ Style Guidelines
Some of these rules are enforced automatically by CI (via clang-format and clang-tidy); others are recommended conventions that will not themselves cause CI failures but should still be followed in code reviews.
**Formatting Rules:**
- **Line length:** 132 characters maximum
- **Indentation:** 2 spaces (never tabs)
- **Braces:** Linux kernel style (opening brace on same line)
```cpp
if (condition) {
// code here
}
```
- **Pointer/reference alignment:** Right side
```cpp
Type *ptr; // Correct
Type &ref; // Correct
Type* ptr; // Wrong
```
- **Empty line after declarations:**
```cpp
void function() {
int x = 5;
std::string name = "test";
// Empty line before first code statement
process_data(x, name);
}
```
- **Always use braces** for if/while/for (no naked conditions):
```cpp
if (x > 0) { // Correct
foo();
}
if (x > 0) // Wrong - missing braces
foo();
```
- **Keep variable declarations together:**
```cpp
// Correct - declarations grouped together
void function() {
int count = 0;
std::string name = "test";
auto *buffer = new_buffer();
// Empty line before first code statement
process_data(count, name, buffer);
}
// Wrong - declarations scattered
void function() {
int count = 0;
process_count(count);
std::string name = "test"; // Don't scatter declarations
}
```
**Naming Conventions:**
- Classes: `CamelCase` → `HttpSM`, `NetVConnection`, `CacheProcessor`
- Functions/variables: `snake_case` → `handle_request()`, `server_port`, `cache_key`
- Constants/macros: `UPPER_CASE` → `HTTP_STATUS_OK`, `MAX_BUFFER_SIZE`
- Private member variables use both `_` and `m_` prefixes in the source code;
be consistent with the surrounding code. For new files, prefer the `_` prefix
because that reflects the community consensus.
- Boolean variables and functions returning boolean values are named as
predicates: use `was_modified` rather than `modified`.
**C++20 Patterns (Use These):**
```cpp
// GOOD - Modern C++20
auto buffer = std::make_unique<MIOBuffer>(size);
for (const auto &entry : container) {
if (auto *ptr = entry.get(); ptr != nullptr) {
process(ptr);
}
}
// AVOID - Legacy C-style
MIOBuffer *buffer = (MIOBuffer*)malloc(sizeof(MIOBuffer));
for (int i = 0; i < container.size(); i++) {
process(container[i]);
}
```
**Memory Management:**
- Use RAII and smart pointers (`std::unique_ptr`, `std::shared_ptr`)
- Prefer smart pointers over raw `new`/`delete` when possible
- Use `ats_malloc()`/`ats_free()` for large allocations (not `malloc`)
- Use `IOBuffer` for network data (zero-copy design)
- Note: Some subsystems legitimately use explicit deletes / `delete this` (e.g., continuation-based code)
**What NOT to Use:**
- ❌ C++23 features (code must compile with C++20)
- ❌ `malloc`/`free` for large allocations (use `ats_malloc`), or prefer heaps or stack allocations
- ❌ Blocking operations in event threads
- ❌ Creating threads manually (use async event system)
### Comments and Documentation
**Minimal comments philosophy:**
- Only add comments where code isn't self-explanatory
- **Don't** describe what the code does (the code already shows that)
- **Do** explain *why* something is done if not obvious
- Avoid stating the obvious
```cpp
// BAD - stating the obvious
// Increment the counter
counter++;
// GOOD - explaining why
// Skip the first element since it's always the sentinel value
counter++;
// BAD - describing what
// Loop through all connections and close them
for (auto &conn : connections) {
conn.close();
}
// GOOD - explaining why (if not obvious)
// Must close connections before destroying the acceptor to avoid use-after-free
for (auto &conn : connections) {
conn.close();
}
```
**When to add comments:**
- Non-obvious algorithms or math
- Workarounds for bugs in dependencies
- Performance optimizations that reduce clarity
- Security-critical sections
- Complex state machine transitions
**When NOT to add comments:**
- Self-documenting code
- Obvious operations
- Function/variable names that explain themselves
### Python Style
- Python 3.11+ with type hints
- 4-space indentation (never tabs)
- Type annotations on all function signatures
- Use f'...' strings rather than .format() strings for new Python code.
### License Headers
**New source and test files** must start with Apache License 2.0 header (`.cc`, `.h`, `.py`, and other code files):
```cpp
/** @file
*
* Brief description of file
*
* @section license License
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
```
## Architecture Patterns
### Event-Driven Model (CRITICAL)
ATS uses **Continuation-based** asynchronous programming:
```cpp
// Continuation is the core callback pattern
class MyContinuation : public Continuation {
int handle_event(int event, void *data) {
switch (event) {
case EVENT_SUCCESS:
// Handle success
return EVENT_DONE;
case EVENT_ERROR:
// Handle error
return EVENT_ERROR;
}
return EVENT_CONT;
}
};
```
**Key Rules:**
- ⚠️ **NEVER block in event threads** - use async I/O or thread pools
- All async operations use `Continuation` callbacks
- Return `EVENT_DONE`, `EVENT_CONT`, or `EVENT_ERROR` from handlers
- Use `EThread::schedule()` for deferred work
### HTTP State Machine
The `HttpSM` class orchestrates HTTP request processing:
```cpp
// HttpSM is the central state machine
class HttpSM : public Continuation {
// Processes requests through various states
// Hook into appropriate stage via plugin hooks
// Access transaction state via HttpTxn
};
```
**Common hooks:**
- `TS_HTTP_READ_REQUEST_HDR_HOOK` - After reading client request
- `TS_HTTP_SEND_REQUEST_HDR_HOOK` - Before sending to origin
- `TS_HTTP_READ_RESPONSE_HDR_HOOK` - After reading origin response
- `TS_HTTP_SEND_RESPONSE_HDR_HOOK` - Before sending to client
### Threading Model
- **Event threads:** Handle most async work (never block here)
- **DNS threads:** Dedicated DNS resolution pool
- **Disk I/O threads:** Cache disk operations
- **Network threads:** Actually event threads handling network I/O
**Rule:** Don't create threads. Use the event system or existing thread pools.
### Debug Logging Pattern
```cpp
// At file scope
static DbgCtl dbg_ctl{"http_sm"};
// In code (preferred)
Dbg(dbg_ctl, "Processing request for URL: %s", url);
// Alternative (less common)
DbgPrint(dbg_ctl, "Processing request for URL: %s", url);
```
**Note:** Use `Dbg()` for new code. `DbgPrint()` exists but is rarely used (~60 vs ~3400 uses).
## Project Structure (Key Paths)
```
trafficserver/
├── src/
│ ├── iocore/ # I/O subsystem
│ │ ├── eventsystem/ # Event engine (Continuation.h is core)
│ │ ├── cache/ # Cache implementation
│ │ ├── net/ # Network I/O, TLS, QUIC
│ │ └── dns/ # DNS resolution
│ ├── proxy/ # HTTP proxy logic
│ │ ├── http/ # HTTP/1.1 (HttpSM.cc is central)
│ │ ├── http2/ # HTTP/2
│ │ ├── http3/ # HTTP/3
│ │ ├── hdrs/ # Header parsing
│ │ └── logging/ # Logging
│ ├── tscore/ # Core utilities
│ ├── tsutil/ # Utilities (metrics, debugging)
│ └── api/ # Plugin API implementation
│
├── include/
│ ├── ts/ # Public plugin API (ts.h)
│ ├── tscpp/ # C++ plugin API
│ └── iocore/ # Internal headers
│
├── plugins/ # Stable plugins
│ ├── header_rewrite/ # Header manipulation (see HRW.instructions.md)
│ └── experimental/ # Experimental plugins
│
└── tools/
└── hrw4u/ # Header Rewrite DSL compiler
```
### Key Files to Understand
- `include/iocore/eventsystem/Continuation.h` - Core async pattern
- `src/proxy/http/HttpSM.cc` - HTTP state machine (most important)
- `src/iocore/cache/Cache.cc` - Cache implementation
- `include/ts/ts.h` - Plugin API (most stable interface)
- `include/tscore/ink_memory.h` - Memory allocation functions
## Common Patterns
### Finding Examples
**Before writing new code, look for similar existing code:**
- Plugin examples: `example/plugins/` for simple patterns
- Stable plugins: `plugins/` for production patterns
- Experimental plugins: `plugins/experimental/` for newer approaches
**Pattern discovery:**
- Search for similar functionality in existing code
- Check `include/ts/ts.h` for plugin API patterns
- Look at tests in `tests/gold_tests/` for usage examples
### Code Organization
**Typical file structure for a plugin:**
```
plugins/my_plugin/
├── my_plugin.cc # Main plugin logic
├── handler.cc # Request/response handlers
├── handler.h # Handler interface
├── config.cc # Configuration parsing
└── CMakeLists.txt # Build configuration
```
**Typical class structure:**
- Inherit from `Continuation` for async operations
- Implement `handle_event()` for event processing
- Store state in class members, not globals
- Clean up resources in destructor (RAII)
### Async Operation Pattern
**General structure for async operations:**
1. Create continuation with callback
2. Initiate async operation (returns `Action*`)
3. Handle callback events in `handle_event()`
4. Return `EVENT_DONE` when complete
**Always async, never blocking:**
- Network I/O → Use VConnection
- Cache operations → Use CacheProcessor
- DNS lookups → Use DNSProcessor
- Delayed work → Use `schedule_in()` or `schedule_at()`
### Error Handling
**Recoverable errors:**
- Return error codes
- Log with appropriate severity
- Clean up resources (RAII helps)
**Unrecoverable errors:**
- Use `ink_release_assert()` for conditions that should never happen
- Log detailed context before asserting
### Testing Approach
**When adding new functionality:**
1. Check if unit tests exist in same directory (Catch2)
2. Add integration tests in `tests/gold_tests/` (autest)
3. Prefer `Test.ATSReplayTest()` with `replay.yaml` format (Proxy Verifier). If
`ATSReplayTest` doesn't fit, prefer organizing the test around a test class with
separate functions for configuring the servers, ATS, client, etc.
4. Test both success and error paths
### AuTest Process Lifetime in Code Reviews
- `StillRunningAfter` and `StillRunningBefore` are assertions about whether a
process is running at a test-run boundary. They do not keep processes alive,
extend their lifetime, or control teardown.
- Omitting an origin, DNS server, or ATS process from `tr.StillRunningAfter`
does not cause AuTest to stop it. Do not request adding a process to this
assertion on every run as a way to preserve it for later runs.
- A process created at `Test` scope and started with `StartBefore` can serve
multiple test runs without appearing in each run's `StillRunningAfter`.
Check the process scope, startup dependencies, and actual shutdown behavior
before reporting a lifetime bug; a missing assertion alone is not evidence.
- Consult the [AuTest TestRun API](https://autestsuite.bitbucket.io/API/testrun.html)
for the assertion and process-ordering semantics.
## Configuration
### Adding New Configuration Records
1. Define in `src/records/RecordsConfig.cc`:
```cpp
{RECT_CONFIG, "proxy.config.my_feature.enabled", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, nullptr, RECA_NULL}
```
2. Read in code:
```cpp
int enabled = 0;
REC_ReadConfigInteger(enabled, "proxy.config.my_feature.enabled");
```
## What to Avoid
### Common Mistakes
❌ **Blocking in event threads:**
```cpp
// WRONG - blocks event thread
sleep(5);
blocking_network_call();
```
✅ **Use async operations:**
```cpp
// CORRECT - schedules continuation
eventProcessor.schedule_in(this, HRTIME_SECONDS(5));
```
❌ **Manual memory management:**
```cpp
// WRONG
auto *obj = new MyObject();
// ... might leak if exception thrown
delete obj;
```
✅ **Use RAII:**
```cpp
// CORRECT
auto obj = std::make_unique<MyObject>();
// Automatically cleaned up
```
❌ **Creating threads:**
```cpp
// WRONG
std::thread t([](){ do_work(); });
```
✅ **Use event system:**
```cpp
// CORRECT
eventProcessor.schedule_imm(continuation, ET_CALL);
```
## Additional Resources
- Plugin API: `include/ts/ts.h`
- Event system: `include/iocore/eventsystem/`
- HTTP state machine: `src/proxy/http/HttpSM.cc`
- Documentation: `doc/developer-guide/`
More agent context in apache/trafficserver
4 other files this repository gives its agents.
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.

