HTTP Alternate Selection

The HTTP alternate selection functions provide a mechanism for hooking into Traffic Server’s alternate selection mechanism and augmenting it with additional information. HTTP alternate selection refers to the process of choosing between several alternate versions of a document for a specific URL. Alternates arise because the HTTP 1.1 specification allows different documents to be sent back for the same URL (depending on the clients request). For example, a server might send back a GIF image to a client that only accepts GIF images, and might send back a JPEG image to a client that only accepts JPEG images.

The alternate selection mechanism is invoked when Traffic Server looks up a URL in its cache. For each URL, Traffic Server stores a vector of alternates. For each alternate in this vector, Traffic Server computes a quality value between 0 and 1 that represents how “good” the alternate is. A quality value of 0 means that the alternate is unacceptable; a value of 1 means that the alternate is a perfect match.

If a plugin hooks onto the TS_HTTP_SELECT_ALT_HOOK, then it will be called back when Traffic Server performs alternate selection. You cannot register locally to the hook TS_HTTP_SELECT_ALT_HOOK by using TSHttpTxnHookAdd - you can only do so by using only TSHttpHookAdd. Since Traffic Server does not actually have an HTTP transaction or an HTTP session on hand when alternate selection is performed, it is only valid to hook onto the global list of TS_HTTP_SELECT_ALT_HOOK. Traffic Server calls each of the select alternate hooks with the TS_EVENT_HTTP_SELECT_ALT event. The void *edata argument that is passed to the continuation is a pointer to an TSHttpAltInfo structure. It can be used later to call the HTTP alternate selection functions listed at the end of this section. Unlike other hooks, this alternate selection callout is non-blocking; the expectation is that the quality value for the alternate will be changed by a call to TSHttpAltInfoQualitySet.


HTTP SM does not have to be reenabled using TSHttpTxnReenable or any other APIs; just return from the function.

The sample code below shows how to call the alternate APIs.

static void handle_select_alt(TSHttpAltInfo infop)
   TSMBuffer client_req_buf, cache_resp_buf;
   TSMLoc client_req_hdr, cache_resp_hdr;

   TSMLoc accept_transform_field;
   TSMLoc content_transform_field;

   int accept_transform_len = -1, content_transform_len = -1;
   const char* accept_transform_value = NULL;
   const char* content_transform_value = NULL;
   int content_plugin, accept_plugin;

   float quality;

   /* get client request, cached request and cached response */
   TSHttpAltInfoClientReqGet (infop, &client_req_buf, &client_req_hdr);
   TSHttpAltInfoCachedRespGet(infop, &cache_resp_buf, &cache_resp_hdr);

   /* get the Accept-Transform field value from the client request */
   accept_transform_field = TSMimeHdrFieldFind(client_req_buf,
      client_req_hdr, "Accept-Transform", -1);
   if (accept_transform_field) {
      TSMimeHdrFieldValueStringGet(client_req_buf, client_req_hdr,
         accept_transform_field, 0, &accept_transform_value, &accept_transform_len);
      TSDebug(DBG_TAG, "Accept-Transform = |%s|",

   /* get the Content-Transform field value from cached server response */
   content_transform_field = TSMimeHdrFieldFind(cache_resp_buf,
      cache_resp_hdr, "Content-Transform", -1);
   if (content_transform_field) {
      TSMimeHdrFieldValueStringGet(cache_resp_buf, cache_resp_hdr,
         content_transform_field, 0, &content_transform_value, &content_transform_len);
      TSDebug(DBG_TAG, "Content-Transform = |%s|",

   /* compute quality */
   accept_plugin = (accept_transform_value && (accept_transform_len > 0) &&
      (strncmp(accept_transform_value, "plugin",
         accept_transform_len) == 0));

   content_plugin = (content_transform_value && (content_transform_len >0) &&
      (strncmp(content_transform_value, "plugin",
         content_transform_len) == 0));

   if (accept_plugin) {
      quality = content_plugin ? 1.0 : 0.0;
   } else {
      quality = content_plugin ? 0.0 : 0.5;

   TSDebug(DBG_TAG, "Setting quality to %3.1f", quality);

   /* set quality for this alternate */
   TSHttpAltInfoQualitySet(infop, quality);

   /* cleanup */
   if (accept_transform_field)
      TSHandleMLocRelease(client_req_buf, client_req_hdr,
   TSHandleMLocRelease(client_req_buf, TS_NULL_MLOC, client_req_hdr);

   if (content_transform_field)
      TSHandleMLocRelease(cache_resp_buf, cache_resp_hdr,
   TSHandleMLocRelease(cache_resp_buf, TS_NULL_MLOC, cache_resp_hdr);

static int alt_plugin(TSCont contp, TSEvent event, void *edata)
   TSHttpAltInfo infop;

   switch (event) {
         infop = (TSHttpAltInfo)edata;


   return 0;

void TSPluginInit (int argc, const char *argv[])
   TSHttpHookAdd(TS_HTTP_SELECT_ALT_HOOK, TSContCreate (alt_plugin,

Traffic Server augments the alternate selection through these callouts using the following algorithm:

  1. Traffic Server computes its own quality value for the alternate, taking into account the quality of the accept match, the encoding match, and the language match.
  2. Traffic Server then calls out each of the continuations on the global TS_HTTP_SELECT_ALT_HOOK’s list.
  3. It multiplies its quality value with the value returned by each callout. Since all of the values are clamped to be between 0 and 1, the final value will be between 0 and 1 as well.
  4. This algorithm also ensures that a single callout can block the usage of a given alternate by specifying a quality value of 0.

A common usage for the alternate selection mechanism is when a plugin transforms a document for some clients and not for others, but wants to store both the transformed and unchanged document. The client’s request will specify whether it accepted the transformed document. The plugin will then determine if the alternate matches this specification and then set the appropriate quality level for the alternate.

The HTTP alternate selection functions are: