Home

Traffic Server Software Developers Kit

Chapter 2. How to Create Traffic Server Plugins

Table of Contents

The Asynchronous Event Model
Traffic Server HTTP State Machine
HTTP Transaction
Types of Hooks
Roadmap for Creating Plugins
Index

This chapter provides a foundation for designing and writing plugins. Reading this chapter will help you to understand:

The Asynchronous Event Model

Traffic Server is a multi-threaded process. There are two main reasons why a server might use multiple threads:

  • To take advantage of the concurrency available with multiple CPUs and multiple I/O devices.

  • To manage concurrency from having many simultaneous client connections. For example, a server could create one thread for each connection, allowing the operating system (OS) to control switching between threads.

Traffic Server uses multiple threads for the first reason. However, Traffic Server does not use a separate OS thread per transaction because it would not be efficient when handling thousands of simultaneous connections.

Instead, Traffic Server provides special event-driven mechanisms for efficiently scheduling work: the event system and continuations. The event system is used to schedule work to be done on threads. A continuation is a passive, event-driven state machine that can do some work until it reaches a waiting point; it then sleeps until it receives notification that conditions are right for doing more work. For example, HTTP state machines (which handle HTTP transactions) are implemented as continuations.

Continuation objects are used throughout Traffic Server. Some might live for the duration of the Traffic Server process, while others are created (perhaps by other continuations) for specific needs and then destroyed. Traffic Server Internals (below) shows how the major components of Traffic Server interact. Traffic Server has several processors, such as cache processor and net processor, that consolidate cache or network I/O tasks. Processors talk to the event system and schedule work on threads. An executing thread calls back a continuation by sending it an event. When a continuation receives an event, it wakes up, does some work, and either destroys itself or goes back to sleep & waits for the next event.

Figure 2.1. Traffic Server Internals

Traffic Server Internals

Plugins are typically implemented as continuations. All of the sample code plugins (except hello-world) are continuations that are created when Traffic Server starts up; they then wait for events that trigger them into activity.

Figure 2.2. Traffic Server with Plugins

Traffic Server with Plugins

A plugin may consist of just one static continuation that is called whenever certain events happen. Examples of such plugins include blacklist-1.c, basic-auth.c, and redirect-1.c. Alternatively, a plugin might dynamically create other continuations as needed. Transform plugins are built in this manner: a static parent continuation checks all transactions to see if any are transformable; when a transaction is transformable, the static continuation creates a type of continuation called a vconnection. The vconnection lives as long as it takes to complete the transform and then destroys itself. This design can be seen in all of the sample transform plugins. Plugins that support new protocols also have this architecture: a static continuation listens for incoming client connections and then creates transaction state machines to handle each protocol transaction.

When you write plugins, there are several ways to send events to continuations. For HTTP plugins, there is a “hook” mechanism that enables the Traffic Server HTTP state machine to send your plugin wakeup calls when needed. Additionally, several Traffic Server API functions trigger Traffic Server sub-processes to send events to plugins: INKContCall, INKVConnRead, INKCacheWrite, and INKMgmtUpdateRegister, to name a few.

Traffic Server HTTP State Machine

Traffic Server performs sophisticated HTTP caching and proxying. Important features include checking for alternates and document freshness, filtering, supporting cache hierarchies, and hosting. Traffic Server handles thousands of client requests at a time and each request is handled by an HTTP state machine. These machines follow a complex state diagram that includes all of the states required to support Traffic Server’s features. The Traffic Server API provides hooks to a subset of these states, chosen for their relevance to plugins. You can view the API hooks and corresponding HTTP states in the HTTP Transaction State Diagram.

The example in this section (below) explains how a plugin typically intervenes and extends Traffic Server’s processing of an HTTP transaction. Complete details about hooking on to Traffic Server processes are provided in HTTP Hooks and Transactions.

HTTP Transaction

An HTTP transaction consists of a client request for a web document and Traffic Server’s response. The response could be the requested web server content or it could be an error message. The content could come from the Traffic Server cache or Traffic Server might fetch it from the origin server. The following diagram shows some states in a typical transaction - specifically, the scenario wherein content is served from cache.

Figure 2.3. Simplified HTTP Transaction

Simplified HTTP Transaction

In the diagram above, Traffic Server accepts the client connection, reads the request headers, looks up the origin server’s IP address, and looks for the requested content in the cache. If the content is not in the cache (a "miss"), then Traffic Server opens a connection to the origin server and issues a request for the content. If the content is in the cache (a "hit"), then Traffic Server checks it for freshness.

If the content is fresh, then Traffic Server sends a reply header to the client. If the content is stale, then Traffic Server opens a connection to the origin server and requests the content. The figure above, Simplified HTTP Transaction, does not show behavior in the event of an error. If there is an error at a any stage, then the HTTP state machine jumps to the “send reply header” state and sends a reply. If the reply is an error, then the transaction closes. If the reply is not an error, then Traffic Server first sends the response content before it closes the transaction.

Figure 2.4. API Hooks Corresponding to States Listed in the previous Simplified HTTP Transaction Diagram

API Hooks Corresponding to States Listed in

You use hooks as triggers to start your plugin. The name of a hook reflects the Traffic Server state that was just completed. For example, the “OS DNS lookup” hook wakes up a plugin right after the origin server DNS lookup. For a plugin that requires the IP address of the requested origin server, this hook is the right one to use. The Blacklist plugin works in this manner, as shown in the Blacklist Plugin diagram below.

Figure 2.5. Blacklist Plugin

Blacklist Plugin

Traffic Server calls the Blacklist plugin right after the origin server DNS lookup. The plugin checks the requested host against a list of blacklisted servers; if the request is allowed, then the transaction proceeds. If the host is forbidden, then the Blacklist plugin sends the transaction into an error state. When the HTTP state machine gets to the “send reply header” state, it then calls the Blacklist plugin to provide the error message that's sent to the client.

Types of Hooks

The Blacklist plugin’s hook to the “origin server DNS lookup” state is a global hook, meaning that the plugin is called every time there's an HTTP transaction with a DNS lookup event. The plugin’s hook to the “send reply header” state is a transaction hook, meaning that this hook is only invoked for specified transactions (in the Blacklist example, it's only used for requests to blacklisted servers). Several examples of setting up hooks are provided in the code example chapters: Header-Based Plugin Examples and HTTP Transformation Plugins.

Header manipulation plugins, such as filtering, basic authorization, or redirects, usually have a global hook to the DNS lookup or the read request header states. If specific actions need to be done to the transaction further on, then the plugin adds itself to a transaction hook. Transformation plugins require a global hook to check all transactions for transformability followed by a transform hook, which is a type of transaction hook used specifically for transforms.