HttpTransact::handle_request_keep_alive_headers(State* s, HTTPVersion ver, HTTPHdr* heads)
{
  enum KA_Action_t
  {
    KA_UNKNOWN,
    KA_DISABLED,
    KA_CLOSE,
    KA_CONNECTION
  };

  KA_Action_t ka_action = KA_UNKNOWN;
  bool upstream_ka = (s->current.server->keep_alive == HTTP_KEEPALIVE);

  ink_assert(heads->type_get() == HTTP_TYPE_REQUEST);

  // Check preconditions for Keep-Alive
  if (!upstream_ka) {
    ka_action = KA_DISABLED;
  } else if (HTTP_MAJOR(ver.m_version) == 0) {  /* No K-A for 0.9 apps */
    ka_action = KA_DISABLED;
  }
  // If preconditions are met, figure out what action to take
  if (ka_action == KA_UNKNOWN) {
    int method = heads->method_get_wksidx();
    if (method == HTTP_WKSIDX_GET ||
        method == HTTP_WKSIDX_HEAD ||
        method == HTTP_WKSIDX_OPTIONS ||
        method == HTTP_WKSIDX_PURGE || method == HTTP_WKSIDX_DELETE || method == HTTP_WKSIDX_TRACE) {
      // These methods do not need a content-length header
      ka_action = KA_CONNECTION;
    } else {
      // All remaining methods require a content length header
      if (heads->get_content_length() == -1) {
        ka_action = KA_CLOSE;
      } else {
        ka_action = KA_CONNECTION;
      }
    }
  }

  ink_assert(ka_action != KA_UNKNOWN);

  // Since connection headers are hop-to-hop, strip the
  //  the ones we received from the user-agent
  heads->field_delete(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION);
  heads->field_delete(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION);

  if (!s->is_upgrade_request) {
    // Insert K-A headers as necessary
    switch (ka_action) {
    case KA_CONNECTION:
      ink_assert(s->current.server->keep_alive != HTTP_NO_KEEPALIVE);
      if (ver == HTTPVersion(1, 0)) {
        if (s->current.request_to == PARENT_PROXY ||
            s->current.request_to == ICP_SUGGESTED_HOST) {
          heads->value_set(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION, "keep-alive", 10);
        } else {
          heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, "keep-alive", 10);
        }
      }
      // NOTE: if the version is 1.1 we don't need to do
      //  anything since keep-alive is assumed
      break;
    case KA_DISABLED:
    case KA_CLOSE:
      if (s->current.server->keep_alive != HTTP_NO_KEEPALIVE || (ver == HTTPVersion(1, 1))) {
        /* Had keep-alive */
        s->current.server->keep_alive = HTTP_NO_KEEPALIVE;
        if (s->current.request_to == PARENT_PROXY ||
            s->current.request_to == ICP_SUGGESTED_HOST) {
          heads->value_set(MIME_FIELD_PROXY_CONNECTION, MIME_LEN_PROXY_CONNECTION, "close", 5);
        } else {
          heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, "close", 5);
        }
      }
      // Note: if we are 1.1, we always need to send the close
      //  header since persistant connnections are the default
      break;
    case KA_UNKNOWN:
    default:
      ink_assert(0);
      break;
    }
  } else { /* websocket connection */
    s->current.server->keep_alive = HTTP_NO_KEEPALIVE;
    s->client_info.keep_alive = HTTP_NO_KEEPALIVE;
    heads->value_set(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION, MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE);

    if (s->is_websocket) {
      heads->value_set(MIME_FIELD_UPGRADE, MIME_LEN_UPGRADE, "websocket", 9);
    }
  }
}                               /* End HttpTransact::handle_request_keep_alive_headers */