http: extendable conn/req ctx and multiplexing 62/42462/7
authorMatus Fabian <[email protected]>
Fri, 7 Mar 2025 13:02:42 +0000 (08:02 -0500)
committerFlorin Coras <[email protected]>
Mon, 24 Mar 2025 17:03:48 +0000 (17:03 +0000)
multiplexing support:
- set request index as connection_index in application session
- do not allocate app session/http req immediately in
  http_ts_accept_callback but wait for request/stream opening

HTTP version specific data in connection and request ctx:
- opaque pointer in http_conn_t
- req_pool manged entirely by specific version engine

Version specific configuration:
- added name to http_engine_vft_t
- added unformat_cfg_callback (optional) to http_engine_vft_t

Type: improvement

Change-Id: Ib43f0489337a222a68b0f81d45cb2e64b2c606c0
Signed-off-by: Matus Fabian <[email protected]>
extras/hs-test/http_test.go
src/plugins/http/http.c
src/plugins/http/http1.c
src/plugins/http/http_private.h
src/plugins/http/http_timer.h

index f4bee5e..760ca3c 100644 (file)
@@ -239,6 +239,23 @@ func HttpCliTest(s *VethsSuite) {
        s.Log(o)
        s.AssertContains(o, "<html>", "<html> not found in the result!")
        s.AssertContains(o, "</html>", "</html> not found in the result!")
+
+       /* test client session cleanup */
+       clientCleanupDone := false
+       for nTries := 0; nTries < 30; nTries++ {
+               o := s.Containers.ClientVpp.VppInstance.Vppctl("show session verbose 2")
+               if !strings.Contains(o, "->"+s.Interfaces.Server.Ip4AddressString()+":80") {
+                       clientCleanupDone = true
+                       break
+               }
+               time.Sleep(1 * time.Second)
+       }
+       s.AssertEqual(true, clientCleanupDone)
+
+       /* test server app stop listen */
+       s.Containers.ServerVpp.VppInstance.Vppctl("http cli server listener del")
+       o = s.Containers.ServerVpp.VppInstance.Vppctl("show session verbose proto http")
+       s.AssertNotContains(o, "LISTEN")
 }
 
 func HttpCliTlsTest(s *VethsSuite) {
index fc5b7d5..5998a9e 100644 (file)
@@ -36,26 +36,6 @@ http_register_engine (const http_engine_vft_t *vft, http_version_t version)
   http_vfts[version] = *vft;
 }
 
-always_inline http_version_t
-http_version_from_handle (http_conn_handle_t hc_handle)
-{
-  /* the first 3 bits are http version */
-  return hc_handle >> 29;
-}
-
-always_inline u32
-http_conn_index_from_handle (http_conn_handle_t hc_handle)
-{
-  return hc_handle & 0x1FFFFFFF;
-}
-
-always_inline http_conn_handle_t
-http_make_handle (u32 hc_index, http_version_t version)
-{
-  ASSERT (hc_index <= 0x1FFFFFFF);
-  return (version << 29) | hc_index;
-}
-
 int
 http_v_find_index (u8 *vec, u32 offset, u32 num, char *str)
 {
@@ -145,13 +125,7 @@ http_conn_alloc_w_thread (u32 thread_index)
   http_conn_t *hc;
 
   pool_get_aligned_safe (wrk->conn_pool, hc, CLIB_CACHE_LINE_BYTES);
-  clib_memset (hc, 0, sizeof (*hc));
-  hc->c_thread_index = thread_index;
-  hc->h_hc_index = hc - wrk->conn_pool;
-  hc->h_pa_session_handle = SESSION_INVALID_HANDLE;
-  hc->h_tc_session_handle = SESSION_INVALID_HANDLE;
-  hc->version = HTTP_VERSION_NA;
-  return hc->h_hc_index;
+  return (hc - wrk->conn_pool);
 }
 
 static inline http_conn_t *
@@ -211,7 +185,7 @@ http_ho_try_free (u32 ho_hc_index)
   if (!(ho_hc->flags & HTTP_CONN_F_HO_DONE))
     {
       HTTP_DBG (1, "postponed cleanup");
-      ho_hc->h_tc_session_handle = SESSION_INVALID_HANDLE;
+      ho_hc->hc_tc_session_handle = SESSION_INVALID_HANDLE;
       http_add_postponed_ho_cleanups (ho_hc_index);
       return;
     }
@@ -247,12 +221,12 @@ http_ho_conn_alloc (void)
 
   pool_get_aligned_safe (hm->ho_conn_pool, hc, CLIB_CACHE_LINE_BYTES);
   clib_memset (hc, 0, sizeof (*hc));
-  hc->h_hc_index = hc - hm->ho_conn_pool;
-  hc->h_pa_session_handle = SESSION_INVALID_HANDLE;
-  hc->h_tc_session_handle = SESSION_INVALID_HANDLE;
+  hc->hc_hc_index = hc - hm->ho_conn_pool;
+  hc->hc_pa_session_handle = SESSION_INVALID_HANDLE;
+  hc->hc_tc_session_handle = SESSION_INVALID_HANDLE;
   hc->timeout = HTTP_CONN_TIMEOUT;
   hc->version = HTTP_VERSION_NA;
-  return hc->h_hc_index;
+  return hc->hc_hc_index;
 }
 
 static u32
@@ -262,10 +236,10 @@ http_listener_alloc (void)
   http_conn_t *lhc;
 
   pool_get_zero (hm->listener_pool, lhc);
-  lhc->h_hc_index = lhc - hm->listener_pool;
+  lhc->hc_hc_index = lhc - hm->listener_pool;
   lhc->timeout = HTTP_CONN_TIMEOUT;
   lhc->version = HTTP_VERSION_NA;
-  return lhc->h_hc_index;
+  return lhc->hc_hc_index;
 }
 
 static http_conn_t *
@@ -289,7 +263,7 @@ void
 http_disconnect_transport (http_conn_t *hc)
 {
   vnet_disconnect_args_t a = {
-    .handle = hc->h_tc_session_handle,
+    .handle = hc->hc_tc_session_handle,
     .app_index = http_main.app_index,
   };
 
@@ -307,14 +281,14 @@ http_sc_by_u16 (u16 status_code)
 }
 
 u8 *
-http_get_app_header_list (http_conn_t *hc, http_msg_t *msg)
+http_get_app_header_list (http_req_t *req, http_msg_t *msg)
 {
   http_main_t *hm = &http_main;
   session_t *as;
   u8 *app_headers;
   int rv;
 
-  as = session_get_from_handle (hc->h_pa_session_handle);
+  as = session_get_from_handle (req->hr_pa_session_handle);
 
   if (msg->data.type == HTTP_MSG_DATA_PTR)
     {
@@ -326,7 +300,7 @@ http_get_app_header_list (http_conn_t *hc, http_msg_t *msg)
     }
   else
     {
-      app_headers = hm->app_header_lists[hc->c_thread_index];
+      app_headers = hm->app_header_lists[as->thread_index];
       rv = svm_fifo_dequeue (as->tx_fifo, msg->data.headers_len, app_headers);
       ASSERT (rv == msg->data.headers_len);
     }
@@ -341,7 +315,7 @@ http_get_app_target (http_req_t *req, http_msg_t *msg)
   u8 *target;
   int rv;
 
-  as = session_get_from_handle (req->app_session_handle);
+  as = session_get_from_handle (req->hr_pa_session_handle);
 
   if (msg->data.type == HTTP_MSG_DATA_PTR)
     {
@@ -384,7 +358,7 @@ http_get_rx_buf (http_conn_t *hc)
 void
 http_req_tx_buffer_init (http_req_t *req, http_msg_t *msg)
 {
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   http_buffer_init (&req->tx_buf, msg_to_buf_type[msg->data.type], as->tx_fifo,
                    msg->data.body_len);
 }
@@ -431,7 +405,7 @@ http_conn_timeout_cb (void *hc_handlep)
       return;
     }
 
-  session_transport_closing_notify (&hc->connection);
+  http_vfts[hc->version].transport_close_callback (hc);
   http_disconnect_transport (hc);
 }
 
@@ -442,11 +416,10 @@ http_conn_timeout_cb (void *hc_handlep)
 int
 http_ts_accept_callback (session_t *ts)
 {
-  session_t *ts_listener, *as, *asl;
-  app_worker_t *app_wrk;
+  session_t *ts_listener;
   http_conn_t *lhc, *hc;
   u32 hc_index, thresh;
-  int rv;
+  http_conn_handle_t hc_handle;
 
   ts_listener = listen_session_get_from_handle (ts->listener_handle);
   lhc = http_listener_get (ts_listener->opaque);
@@ -456,61 +429,27 @@ http_ts_accept_callback (session_t *ts)
   clib_memcpy_fast (hc, lhc, sizeof (*lhc));
   hc->timer_handle = HTTP_TIMER_HANDLE_INVALID;
   hc->c_thread_index = ts->thread_index;
-  hc->h_hc_index = hc_index;
-
-  hc->h_tc_session_handle = session_handle (ts);
+  hc->hc_hc_index = hc_index;
+  hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
+  hc->hc_tc_session_handle = session_handle (ts);
   hc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
   hc->state = HTTP_CONN_STATE_ESTABLISHED;
 
   ts->session_state = SESSION_STATE_READY;
-  /* TODO: TLS set by ALPN result, TCP: first try HTTP/1 */
+  /* TODO: TLS set by ALPN result, TCP: will decide in http_ts_rx_callback */
   hc->version = HTTP_VERSION_1;
-  ts->opaque = http_make_handle (hc_index, hc->version);
-
-  /*
-   * Alloc session and initialize
-   */
-  as = session_alloc (hc->c_thread_index);
-  hc->c_s_index = as->session_index;
-
-  as->app_wrk_index = hc->h_pa_wrk_index;
-  as->connection_index = hc->h_hc_index;
-  as->session_state = SESSION_STATE_ACCEPTING;
-
-  asl = listen_session_get_from_handle (lhc->h_pa_session_handle);
-  as->session_type = asl->session_type;
-  as->listener_handle = lhc->h_pa_session_handle;
-
-  /*
-   * Init session fifos and notify app
-   */
-  if ((rv = app_worker_init_accepted (as)))
-    {
-      HTTP_DBG (1, "failed to allocate fifos");
-      hc->h_pa_session_handle = SESSION_INVALID_HANDLE;
-      session_free (as);
-      return rv;
-    }
-
-  hc->h_pa_session_handle = session_handle (as);
-  hc->h_pa_wrk_index = as->app_wrk_index;
-  app_wrk = app_worker_get (as->app_wrk_index);
+  hc_handle.version = hc->version;
+  hc_handle.conn_index = hc_index;
+  ts->opaque = hc_handle.as_u32;
 
   HTTP_DBG (1, "Accepted on listener %u new connection [%u]%x",
            ts_listener->opaque, vlib_get_thread_index (), hc_index);
 
-  if ((rv = app_worker_accept_notify (app_wrk, as)))
-    {
-      HTTP_DBG (0, "app accept returned");
-      session_free (as);
-      return rv;
-    }
-
   /* Avoid enqueuing small chunks of data on transport tx notifications. If
    * the fifo is small (under 16K) we set the threshold to it's size, meaning
    * a notification will be given when the fifo empties.
    */
-  ts = session_get_from_handle (hc->h_tc_session_handle);
+  ts = session_get_from_handle (hc->hc_tc_session_handle);
   thresh = clib_min (svm_fifo_size (ts->tx_fifo), HTTP_FIFO_THRESH);
   svm_fifo_set_deq_thresh (ts->tx_fifo, thresh);
 
@@ -524,9 +463,9 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts,
                            session_error_t err)
 {
   u32 new_hc_index;
-  session_t *as;
   http_conn_t *hc, *ho_hc;
   app_worker_t *app_wrk;
+  http_conn_handle_t hc_handle;
   int rv;
 
   ho_hc = http_ho_conn_get (ho_hc_index);
@@ -537,9 +476,9 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts,
       clib_warning ("half-open hc index %d, error: %U", ho_hc_index,
                    format_session_error, err);
       ho_hc->flags |= HTTP_CONN_F_HO_DONE;
-      app_wrk = app_worker_get_if_valid (ho_hc->h_pa_wrk_index);
+      app_wrk = app_worker_get_if_valid (ho_hc->hc_pa_wrk_index);
       if (app_wrk)
-       app_worker_connect_notify (app_wrk, 0, err, ho_hc->h_pa_app_api_ctx);
+       app_worker_connect_notify (app_wrk, 0, err, ho_hc->hc_pa_app_api_ctx);
       return 0;
     }
 
@@ -553,43 +492,26 @@ http_ts_connected_callback (u32 http_app_index, u32 ho_hc_index, session_t *ts,
 
   hc->timer_handle = HTTP_TIMER_HANDLE_INVALID;
   hc->c_thread_index = ts->thread_index;
-  hc->h_tc_session_handle = session_handle (ts);
-  hc->h_hc_index = new_hc_index;
+  hc->hc_tc_session_handle = session_handle (ts);
+  hc->hc_hc_index = new_hc_index;
   hc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
   hc->state = HTTP_CONN_STATE_ESTABLISHED;
   ts->session_state = SESSION_STATE_READY;
+  hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
   /* TODO: TLS set by ALPN result, TCP: prior knowledge (set in ho) */
-  ts->opaque = http_make_handle (new_hc_index, hc->version);
-
-  /* allocate app session and initialize */
-
-  as = session_alloc (hc->c_thread_index);
-  hc->c_s_index = as->session_index;
-  as->connection_index = new_hc_index;
-  as->app_wrk_index = hc->h_pa_wrk_index;
-  as->session_state = SESSION_STATE_READY;
-  as->opaque = hc->h_pa_app_api_ctx;
-  as->session_type = session_type_from_proto_and_ip (
-    TRANSPORT_PROTO_HTTP, session_type_is_ip4 (ts->session_type));
+  hc_handle.version = hc->version;
+  hc_handle.conn_index = new_hc_index;
+  ts->opaque = hc_handle.as_u32;
 
   HTTP_DBG (1, "half-open hc index %x,  hc [%u]%x", ho_hc_index,
            ts->thread_index, new_hc_index);
 
-  app_wrk = app_worker_get (hc->h_pa_wrk_index);
-  if (!app_wrk)
-    {
-      clib_warning ("no app worker");
-      return -1;
-    }
-
-  if ((rv = app_worker_init_connected (app_wrk, as)))
+  if ((rv = http_vfts[hc->version].transport_connected_callback (hc)))
     {
-      HTTP_DBG (1, "failed to allocate fifos");
-      session_free (as);
+      clib_warning ("transport_connected_callback failed, rv=%d", rv);
       return rv;
     }
-  app_worker_connect_notify (app_wrk, as, err, hc->h_pa_app_api_ctx);
-  hc->h_pa_session_handle = session_handle (as);
+
   http_conn_timer_start (hc);
 
   return 0;
@@ -599,11 +521,13 @@ static void
 http_ts_disconnect_callback (session_t *ts)
 {
   http_conn_t *hc;
-  u32 hc_index = http_conn_index_from_handle (ts->opaque);
+  http_conn_handle_t hc_handle;
+
+  hc_handle.as_u32 = ts->opaque;
 
   HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index);
 
-  hc = http_conn_get_w_thread (hc_index, ts->thread_index);
+  hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index);
 
   if (hc->state < HTTP_CONN_STATE_TRANSPORT_CLOSED)
     hc->state = HTTP_CONN_STATE_TRANSPORT_CLOSED;
@@ -615,14 +539,16 @@ static void
 http_ts_reset_callback (session_t *ts)
 {
   http_conn_t *hc;
-  u32 hc_index = http_conn_index_from_handle (ts->opaque);
+  http_conn_handle_t hc_handle;
+
+  hc_handle.as_u32 = ts->opaque;
 
   HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index);
 
-  hc = http_conn_get_w_thread (hc_index, ts->thread_index);
+  hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index);
 
   hc->state = HTTP_CONN_STATE_CLOSED;
-  session_transport_reset_notify (&hc->connection);
+  http_vfts[hc->version].transport_reset_callback (hc);
 
   http_disconnect_transport (hc);
 }
@@ -631,11 +557,13 @@ static int
 http_ts_rx_callback (session_t *ts)
 {
   http_conn_t *hc;
-  u32 hc_index = http_conn_index_from_handle (ts->opaque);
+  http_conn_handle_t hc_handle;
 
-  HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index);
+  hc_handle.as_u32 = ts->opaque;
 
-  hc = http_conn_get_w_thread (hc_index, ts->thread_index);
+  HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_handle.conn_index);
+
+  hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index);
 
   if (hc->state == HTTP_CONN_STATE_CLOSED)
     {
@@ -644,13 +572,11 @@ http_ts_rx_callback (session_t *ts)
       return 0;
     }
 
-  http_vfts[http_version_from_handle (ts->opaque)].transport_rx_callback (hc);
+  /* TODO: if version is unknown */
+  http_vfts[hc_handle.version].transport_rx_callback (hc);
 
   if (hc->state == HTTP_CONN_STATE_TRANSPORT_CLOSED)
-    {
-      if (!svm_fifo_max_dequeue_cons (ts->rx_fifo))
-       session_transport_closing_notify (&hc->connection);
-    }
+    http_vfts[hc->version].transport_close_callback (hc);
   return 0;
 }
 
@@ -658,11 +584,13 @@ int
 http_ts_builtin_tx_callback (session_t *ts)
 {
   http_conn_t *hc;
+  http_conn_handle_t hc_handle;
 
-  hc = http_conn_get_w_thread (http_conn_index_from_handle (ts->opaque),
-                              ts->thread_index);
+  hc_handle.as_u32 = ts->opaque;
+
+  hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index);
   HTTP_DBG (1, "transport connection reschedule");
-  transport_connection_reschedule (&hc->connection);
+  http_vfts[hc->version].transport_conn_reschedule_callback (hc);
 
   return 0;
 }
@@ -671,29 +599,20 @@ static void
 http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf)
 {
   http_conn_t *hc;
-  http_req_t *req;
-  u32 hc_index;
+  http_conn_handle_t hc_handle;
 
   if (ntf == SESSION_CLEANUP_TRANSPORT)
     return;
 
-  hc_index = http_conn_index_from_handle (ts->opaque);
-  hc = http_conn_get_w_thread (hc_index, ts->thread_index);
+  hc_handle.as_u32 = ts->opaque;
+  hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index);
 
   HTTP_DBG (1, "going to free hc [%u]%x", ts->thread_index, hc_index);
 
-  pool_foreach (req, hc->req_pool)
-    {
-      vec_free (req->headers);
-      vec_free (req->target);
-      http_buffer_free (&req->tx_buf);
-    }
-  pool_free (hc->req_pool);
-
   if (!(hc->flags & HTTP_CONN_F_PENDING_TIMER))
     http_conn_timer_stop (hc);
 
-  session_transport_delete_notify (&hc->connection);
+  http_vfts[hc->version].conn_cleanup_callback (hc);
 
   if (!(hc->flags & HTTP_CONN_F_IS_SERVER))
     {
@@ -706,9 +625,8 @@ http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf)
 static void
 http_ts_ho_cleanup_callback (session_t *ts)
 {
-  u32 ho_hc_index = http_conn_index_from_handle (ts->opaque);
-  HTTP_DBG (1, "half open: %x", ho_hc_index);
-  http_ho_try_free (ho_hc_index);
+  HTTP_DBG (1, "half open: %x", ts->opaque);
+  http_ho_try_free (ts->opaque);
 }
 
 int
@@ -750,6 +668,7 @@ http_transport_enable (vlib_main_t *vm, u8 is_en)
   u64 options[APP_OPTIONS_N_OPTIONS];
   http_main_t *hm = &http_main;
   u32 num_threads, i;
+  http_engine_vft_t *http_version;
 
   if (!is_en)
     {
@@ -806,6 +725,12 @@ http_transport_enable (vlib_main_t *vm, u8 is_en)
   http_timers_init (vm, http_conn_timeout_cb, http_conn_invalidate_timer_cb);
   hm->is_init = 1;
 
+  vec_foreach (http_version, http_vfts)
+    {
+      if (http_version->enable_callback)
+       http_version->enable_callback ();
+    }
+
   return 0;
 }
 
@@ -832,10 +757,10 @@ http_transport_connect (transport_endpoint_cfg_t *tep)
 
   hc_index = http_ho_conn_alloc ();
   hc = http_ho_conn_get (hc_index);
-  hc->h_pa_wrk_index = sep->app_wrk_index;
-  hc->h_pa_app_api_ctx = sep->opaque;
+  hc->hc_pa_wrk_index = sep->app_wrk_index;
+  hc->hc_pa_app_api_ctx = sep->opaque;
   hc->state = HTTP_CONN_STATE_CONNECTING;
-  /* TODO: set to HTTP_VERSION_NA in case of TLS (when supported) */
+  /* TODO: set to HTTP_VERSION_NA in case of TLS */
   hc->version = HTTP_VERSION_1;
   cargs->api_context = hc_index;
 
@@ -878,7 +803,7 @@ http_transport_connect (transport_endpoint_cfg_t *tep)
   ho->opaque = sep->opaque;
   ho->session_type =
     session_type_from_proto_and_ip (TRANSPORT_PROTO_HTTP, sep->is_ip4);
-  hc->h_tc_session_handle = cargs->sh;
+  hc->hc_tc_session_handle = cargs->sh;
   hc->c_s_index = ho->session_index;
 
   return 0;
@@ -933,15 +858,15 @@ http_start_listen (u32 app_listener_index, transport_endpoint_cfg_t *tep)
     }
 
   /* Grab transport connection listener and link to http listener */
-  lhc->h_tc_session_handle = args->handle;
-  al = app_listener_get_w_handle (lhc->h_tc_session_handle);
+  lhc->hc_tc_session_handle = args->handle;
+  al = app_listener_get_w_handle (lhc->hc_tc_session_handle);
   ts_listener = app_listener_get_session (al);
   ts_listener->opaque = lhc_index;
 
   /* Grab application listener and link to http listener */
   app_listener = listen_session_get (app_listener_index);
-  lhc->h_pa_wrk_index = sep->app_wrk_index;
-  lhc->h_pa_session_handle = listen_session_get_handle (app_listener);
+  lhc->hc_pa_wrk_index = sep->app_wrk_index;
+  lhc->hc_pa_session_handle = listen_session_get_handle (app_listener);
   lhc->c_s_index = app_listener_index;
   lhc->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
 
@@ -964,7 +889,7 @@ http_stop_listen (u32 listener_index)
   lhc = http_listener_get (listener_index);
 
   vnet_unlisten_args_t a = {
-    .handle = lhc->h_tc_session_handle,
+    .handle = lhc->hc_tc_session_handle,
     .app_index = http_main.app_index,
     .wrk_map_index = 0 /* default wrk */
   };
@@ -978,15 +903,22 @@ http_stop_listen (u32 listener_index)
 }
 
 static void
-http_transport_close (u32 hc_index, u32 thread_index)
+http_transport_close (u32 rh, u32 thread_index)
 {
   http_conn_t *hc;
+  u32 hc_index;
+  http_req_handle_t hr_handle;
 
+  hr_handle.as_u32 = rh;
+
+  hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index (
+    hr_handle.req_index, thread_index);
   HTTP_DBG (1, "App disconnecting [%u]%x", thread_index, hc_index);
 
   hc = http_conn_get_w_thread (hc_index, thread_index);
   if (hc->state == HTTP_CONN_STATE_CONNECTING)
     {
+      HTTP_DBG (1, "in connecting state, close now");
       hc->state = HTTP_CONN_STATE_APP_CLOSED;
       http_disconnect_transport (hc);
       return;
@@ -997,14 +929,20 @@ http_transport_close (u32 hc_index, u32 thread_index)
       return;
     }
 
-  http_vfts[hc->version].app_close_callback (hc);
+  http_vfts[hc->version].app_close_callback (hc, hr_handle.req_index,
+                                            thread_index);
 }
 
 static void
-http_transport_reset (u32 hc_index, u32 thread_index)
+http_transport_reset (u32 rh, u32 thread_index)
 {
   http_conn_t *hc;
+  u32 hc_index;
+  http_req_handle_t hr_handle;
 
+  hr_handle.as_u32 = rh;
+  hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index (
+    hr_handle.req_index, thread_index);
   HTTP_DBG (1, "App disconnecting [%u]%x", thread_index, hc_index);
 
   hc = http_conn_get_w_thread (hc_index, thread_index);
@@ -1014,14 +952,18 @@ http_transport_reset (u32 hc_index, u32 thread_index)
       return;
     }
 
-  http_vfts[hc->version].app_reset_callback (hc);
+  http_vfts[hc->version].app_reset_callback (hc, hr_handle.req_index,
+                                            thread_index);
 }
 
 static transport_connection_t *
-http_transport_get_connection (u32 hc_index, u32 thread_index)
+http_transport_get_connection (u32 rh, u32 thread_index)
 {
-  http_conn_t *hc = http_conn_get_w_thread (hc_index, thread_index);
-  return &hc->connection;
+  http_req_handle_t hr_handle;
+
+  hr_handle.as_u32 = rh;
+  return http_vfts[hr_handle.version].req_get_connection (hr_handle.req_index,
+                                                         thread_index);
 }
 
 static transport_connection_t *
@@ -1035,12 +977,16 @@ static int
 http_app_tx_callback (void *session, transport_send_params_t *sp)
 {
   session_t *as = (session_t *) session;
-  u32 max_burst_sz, sent;
+  u32 max_burst_sz, sent, hc_index;
   http_conn_t *hc;
+  http_req_handle_t hr_handle;
+  hr_handle.as_u32 = as->connection_index;
 
-  HTTP_DBG (1, "hc [%u]%x", as->thread_index, as->connection_index);
+  hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index (
+    hr_handle.req_index, as->thread_index);
+  HTTP_DBG (1, "hc [%u]%x", hc_index, as->connection_index);
 
-  hc = http_conn_get_w_thread (as->connection_index, as->thread_index);
+  hc = http_conn_get_w_thread (hc_index, as->thread_index);
 
   if (hc->state == HTTP_CONN_STATE_CLOSED)
     {
@@ -1052,16 +998,11 @@ http_app_tx_callback (void *session, transport_send_params_t *sp)
   max_burst_sz = sp->max_burst_size * TRANSPORT_PACER_MIN_MSS;
   sp->max_burst_size = max_burst_sz;
 
-  http_vfts[hc->version].app_tx_callback (hc, sp);
+  http_vfts[hc->version].app_tx_callback (hc, hr_handle.req_index, sp);
 
   if (hc->state == HTTP_CONN_STATE_APP_CLOSED)
-    {
-      if (!svm_fifo_max_dequeue_cons (as->tx_fifo))
-       {
-         session_transport_closed_notify (&hc->connection);
-         http_disconnect_transport (hc);
-       }
-    }
+    http_vfts[hc->version].app_close_callback (hc, hr_handle.req_index,
+                                              as->thread_index);
 
   sent = max_burst_sz - sp->max_burst_size;
 
@@ -1071,37 +1012,36 @@ http_app_tx_callback (void *session, transport_send_params_t *sp)
 static int
 http_app_rx_evt_cb (transport_connection_t *tc)
 {
-  http_conn_t *hc = (http_conn_t *) tc;
-  HTTP_DBG (1, "hc [%u]%x", vlib_get_thread_index (), hc->h_hc_index);
+  http_req_t *req = (http_req_t *) tc;
+  http_conn_t *hc;
+  http_req_handle_t hr_handle;
+
+  HTTP_DBG (1, "hc [%u]%x", vlib_get_thread_index (), req->hr_hc_index);
 
-  http_vfts[hc->version].app_rx_evt_callback (hc);
+  hr_handle.as_u32 = req->hr_req_handle;
+  hc = http_conn_get_w_thread (req->hr_hc_index, req->c_thread_index);
+  http_vfts[hr_handle.version].app_rx_evt_callback (hc, hr_handle.req_index,
+                                                   req->c_thread_index);
 
   return 0;
 }
 
 static void
-http_transport_get_endpoint (u32 hc_index, u32 thread_index,
+http_transport_get_endpoint (u32 rh, u32 thread_index,
                             transport_endpoint_t *tep, u8 is_lcl)
 {
-  http_conn_t *hc = http_conn_get_w_thread (hc_index, thread_index);
-  session_t *ts;
-
-  ts = session_get_from_handle (hc->h_tc_session_handle);
-  session_get_endpoint (ts, tep, is_lcl);
-}
-
-static u8 *
-format_http_connection (u8 *s, va_list *args)
-{
-  http_conn_t *hc = va_arg (*args, http_conn_t *);
+  http_conn_t *hc;
   session_t *ts;
+  u32 hc_index;
+  http_req_handle_t hr_handle;
 
-  ts = session_get_from_handle (hc->h_tc_session_handle);
-  s = format (s, "[%d:%d][H] app_wrk %u ts %d:%d", hc->c_thread_index,
-             hc->c_s_index, hc->h_pa_wrk_index, ts->thread_index,
-             ts->session_index);
+  hr_handle.as_u32 = rh;
+  hc_index = http_vfts[hr_handle.version].hc_index_get_by_req_index (
+    hr_handle.req_index, thread_index);
+  hc = http_conn_get_w_thread (hc_index, thread_index);
 
-  return s;
+  ts = session_get_from_handle (hc->hc_tc_session_handle);
+  session_get_endpoint (ts, tep, is_lcl);
 }
 
 static u8 *
@@ -1111,10 +1051,10 @@ format_http_listener (u8 *s, va_list *args)
   app_listener_t *al;
   session_t *lts;
 
-  al = app_listener_get_w_handle (lhc->h_tc_session_handle);
+  al = app_listener_get_w_handle (lhc->hc_tc_session_handle);
   lts = app_listener_get_session (al);
   s = format (s, "[%d:%d][H] app_wrk %u ts %d:%d", lhc->c_thread_index,
-             lhc->c_s_index, lhc->h_pa_wrk_index, lts->thread_index,
+             lhc->c_s_index, lhc->hc_pa_wrk_index, lts->thread_index,
              lts->session_index);
 
   return s;
@@ -1123,22 +1063,18 @@ format_http_listener (u8 *s, va_list *args)
 static u8 *
 format_http_transport_connection (u8 *s, va_list *args)
 {
-  u32 tc_index = va_arg (*args, u32);
+  http_req_handle_t rh = va_arg (*args, http_req_handle_t);
   u32 thread_index = va_arg (*args, u32);
   u32 verbose = va_arg (*args, u32);
+  u32 hc_index;
   http_conn_t *hc;
 
-  hc = http_conn_get_w_thread (tc_index, thread_index);
-
-  s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_http_connection, hc);
-  if (verbose)
-    {
-      s =
-       format (s, "%-" SESSION_CLI_STATE_LEN "U", format_http_conn_state, hc);
-      if (verbose > 1)
-       s = format (s, "\n");
-    }
+  hc_index = http_vfts[rh.version].hc_index_get_by_req_index (rh.req_index,
+                                                             thread_index);
+  hc = http_conn_get_w_thread (hc_index, thread_index);
 
+  s = format (s, "%U", http_vfts[rh.version].format_req, rh.req_index,
+             thread_index, hc, verbose);
   return s;
 }
 
@@ -1167,10 +1103,10 @@ format_http_transport_half_open (u8 *s, va_list *args)
   session_t *tcp_ho;
 
   ho_hc = http_ho_conn_get (ho_index);
-  tcp_ho = session_get_from_handle (ho_hc->h_tc_session_handle);
+  tcp_ho = session_get_from_handle (ho_hc->hc_tc_session_handle);
 
   s = format (s, "[%d:%d][H] half-open app_wrk %u ts %d:%d",
-             ho_hc->c_thread_index, ho_hc->c_s_index, ho_hc->h_pa_wrk_index,
+             ho_hc->c_thread_index, ho_hc->c_s_index, ho_hc->hc_pa_wrk_index,
              tcp_ho->thread_index, tcp_ho->session_index);
   return s;
 }
@@ -1192,13 +1128,13 @@ http_transport_cleanup_ho (u32 ho_hc_index)
 
   HTTP_DBG (1, "half open: %x", ho_hc_index);
   ho_hc = http_ho_conn_get (ho_hc_index);
-  if (ho_hc->h_tc_session_handle == SESSION_INVALID_HANDLE)
+  if (ho_hc->hc_tc_session_handle == SESSION_INVALID_HANDLE)
     {
       HTTP_DBG (1, "already pending cleanup");
       ho_hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
       return;
     }
-  session_cleanup_half_open (ho_hc->h_tc_session_handle);
+  session_cleanup_half_open (ho_hc->hc_tc_session_handle);
   http_ho_conn_free (ho_hc);
 }
 
@@ -1267,6 +1203,28 @@ http_transport_init (vlib_main_t *vm)
 
 VLIB_INIT_FUNCTION (http_transport_init);
 
+static uword
+unformat_http_version_cfg (unformat_input_t *input, va_list *va)
+{
+  http_engine_vft_t *http_version;
+  unformat_input_t sub_input;
+  int found = 0;
+
+  vec_foreach (http_version, http_vfts)
+    {
+      if (!unformat (input, http_version->name))
+       continue;
+
+      if (http_version->unformat_cfg_callback &&
+         unformat (input, "%U", unformat_vlib_cli_sub_input, &sub_input))
+       {
+         if (http_version->unformat_cfg_callback (&sub_input))
+           found = 1;
+       }
+    }
+  return found;
+}
+
 static clib_error_t *
 http_config_fn (vlib_main_t *vm, unformat_input_t *input)
 {
@@ -1295,6 +1253,8 @@ http_config_fn (vlib_main_t *vm, unformat_input_t *input)
          if (hm->fifo_size != mem_sz)
            clib_warning ("invalid fifo size %lu", mem_sz);
        }
+      else if (unformat (input, "%U", unformat_http_version_cfg))
+       ;
       else
        return clib_error_return (0, "unknown input `%U'",
                                  format_unformat_error, input);
index c152956..ec118aa 100644 (file)
 #include <http/http_status_codes.h>
 #include <http/http_timer.h>
 
+typedef struct http1_main_
+{
+  http_req_t **req_pool;
+} http1_main_t;
+
+static http1_main_t http1_main;
+
 const char *http1_upgrade_proto_str[] = { "",
 #define _(sym, str) str,
                                          foreach_http_upgrade_proto
@@ -48,6 +55,76 @@ static const char *post_request_template = "POST %s HTTP/1.1\r\n"
                                           "User-Agent: %v\r\n"
                                           "Content-Length: %llu\r\n";
 
+always_inline http_req_t *
+http1_conn_alloc_req (http_conn_t *hc)
+{
+  http1_main_t *h1m = &http1_main;
+  http_req_t *req;
+  u32 req_index;
+  http_req_handle_t hr_handle;
+
+  pool_get_aligned_safe (h1m->req_pool[hc->c_thread_index], req,
+                        CLIB_CACHE_LINE_BYTES);
+  clib_memset (req, 0, sizeof (*req));
+  req->hr_pa_session_handle = SESSION_INVALID_HANDLE;
+  req_index = req - h1m->req_pool[hc->c_thread_index];
+  hr_handle.version = HTTP_VERSION_1;
+  hr_handle.req_index = req_index;
+  req->hr_req_handle = hr_handle.as_u32;
+  req->hr_hc_index = hc->hc_hc_index;
+  req->c_thread_index = hc->c_thread_index;
+  req->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
+  hc->opaque = uword_to_pointer (req_index, void *);
+  hc->flags |= HTTP_CONN_F_HAS_REQUEST;
+  return req;
+}
+
+always_inline http_req_t *
+http1_req_get (u32 req_index, u32 thread_index)
+{
+  http1_main_t *h1m = &http1_main;
+
+  return pool_elt_at_index (h1m->req_pool[thread_index], req_index);
+}
+
+always_inline http_req_t *
+http1_req_get_if_valid (u32 req_index, u32 thread_index)
+{
+  http1_main_t *h1m = &http1_main;
+
+  if (pool_is_free_index (h1m->req_pool[thread_index], req_index))
+    return 0;
+  return pool_elt_at_index (h1m->req_pool[thread_index], req_index);
+}
+
+always_inline http_req_t *
+http1_conn_get_req (http_conn_t *hc)
+{
+  http1_main_t *h1m = &http1_main;
+  u32 req_index;
+
+  req_index = pointer_to_uword (hc->opaque);
+  return pool_elt_at_index (h1m->req_pool[hc->c_thread_index], req_index);
+}
+
+always_inline void
+http1_conn_free_req (http_conn_t *hc)
+{
+  http1_main_t *h1m = &http1_main;
+  http_req_t *req;
+  u32 req_index;
+
+  req_index = pointer_to_uword (hc->opaque);
+  req = pool_elt_at_index (h1m->req_pool[hc->c_thread_index], req_index);
+  vec_free (req->headers);
+  vec_free (req->target);
+  http_buffer_free (&req->tx_buf);
+  if (CLIB_DEBUG)
+    memset (req, 0xba, sizeof (*req));
+  pool_put (h1m->req_pool[hc->c_thread_index], req);
+  hc->flags &= ~HTTP_CONN_F_HAS_REQUEST;
+}
+
 static void
 http1_send_error (http_conn_t *hc, http_status_code_t ec,
                  transport_send_params_t *sp)
@@ -730,13 +807,13 @@ http1_target_fixup (http_conn_t *hc, http_req_t *req)
 }
 
 static void
-http1_write_app_headers (http_conn_t *hc, http_msg_t *msg, u8 **tx_buf)
+http1_write_app_headers (http_req_t *req, http_msg_t *msg, u8 **tx_buf)
 {
   u8 *app_headers, *p, *end;
   u32 *tmp;
 
   /* read app header list */
-  app_headers = http_get_app_header_list (hc, msg);
+  app_headers = http_get_app_header_list (req, msg);
 
   /* serialize app headers to tx_buf */
   end = app_headers + msg->data.headers_len;
@@ -871,8 +948,8 @@ http1_req_state_wait_transport_reply (http_conn_t *hc, http_req_t *req,
 error:
   http_io_ts_drain_all (hc);
   http_io_ts_after_read (hc, 1);
-  session_transport_closing_notify (&hc->connection);
-  session_transport_closed_notify (&hc->connection);
+  session_transport_closing_notify (&req->connection);
+  session_transport_closed_notify (&req->connection);
   http_disconnect_transport (hc);
   return HTTP_SM_ERROR;
 }
@@ -978,7 +1055,7 @@ error:
   http_io_ts_drain_all (hc);
   http_io_ts_after_read (hc, 1);
   http1_send_error (hc, ec, 0);
-  session_transport_closing_notify (&hc->connection);
+  session_transport_closing_notify (&req->connection);
   http_disconnect_transport (hc);
 
   return HTTP_SM_ERROR;
@@ -1015,7 +1092,7 @@ http1_req_state_transport_io_more_data (http_conn_t *hc, http_req_t *req,
   if (n_written > req->to_recv)
     {
       clib_warning ("http protocol error: received more data than expected");
-      session_transport_closing_notify (&hc->connection);
+      session_transport_closing_notify (&req->connection);
       http_disconnect_transport (hc);
       http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD);
       return HTTP_SM_ERROR;
@@ -1117,8 +1194,8 @@ http1_req_state_udp_tunnel_rx (http_conn_t *hc, http_req_t *req,
            {
              /* capsule datagram is invalid (session need to be aborted) */
              http_io_ts_drain_all (hc);
-             session_transport_closing_notify (&hc->connection);
-             session_transport_closed_notify (&hc->connection);
+             session_transport_closing_notify (&req->connection);
+             session_transport_closed_notify (&req->connection);
              http_disconnect_transport (hc);
              return HTTP_SM_STOP;
            }
@@ -1262,7 +1339,7 @@ http1_req_state_wait_app_reply (http_conn_t *hc, http_req_t *req,
   if (msg.data.headers_len)
     {
       HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
-      http1_write_app_headers (hc, &msg, &response);
+      http1_write_app_headers (req, &msg, &response);
     }
   /* Add empty line after headers */
   response = format (response, "\r\n");
@@ -1297,7 +1374,7 @@ http1_req_state_wait_app_reply (http_conn_t *hc, http_req_t *req,
 
 error:
   http1_send_error (hc, sc, sp);
-  session_transport_closing_notify (&hc->connection);
+  session_transport_closing_notify (&req->connection);
   http_disconnect_transport (hc);
   return HTTP_SM_STOP;
 }
@@ -1392,7 +1469,7 @@ http1_req_state_wait_app_method (http_conn_t *hc, http_req_t *req,
   if (msg.data.headers_len)
     {
       HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
-      http1_write_app_headers (hc, &msg, &request);
+      http1_write_app_headers (req, &msg, &request);
     }
   /* Add empty line after headers */
   request = format (request, "\r\n");
@@ -1414,8 +1491,8 @@ http1_req_state_wait_app_method (http_conn_t *hc, http_req_t *req,
 
 error:
   http_io_as_drain_all (req);
-  session_transport_closing_notify (&hc->connection);
-  session_transport_closed_notify (&hc->connection);
+  session_transport_closing_notify (&req->connection);
+  session_transport_closed_notify (&req->connection);
   http_disconnect_transport (hc);
 
 done:
@@ -1617,20 +1694,69 @@ http1_req_run_state_machine (http_conn_t *hc, http_req_t *req,
 /* http core VFT */
 /*****************/
 
-static void
-http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp)
+static u32
+http1_hc_index_get_by_req_index (u32 req_index, u32 thread_index)
 {
   http_req_t *req;
 
-  req = http_get_req_if_valid (hc, 0);
-  if (!req)
+  req = http1_req_get (req_index, thread_index);
+  return req->hr_hc_index;
+}
+
+static transport_connection_t *
+http1_req_get_connection (u32 req_index, u32 thread_index)
+{
+  http_req_t *req;
+  req = http1_req_get (req_index, thread_index);
+  return &req->connection;
+}
+
+static u8 *
+format_http1_req (u8 *s, va_list *args)
+{
+  http_req_t *req = va_arg (*args, http_req_t *);
+  http_conn_t *hc = va_arg (*args, http_conn_t *);
+  session_t *ts;
+
+  ts = session_get_from_handle (hc->hc_tc_session_handle);
+  s = format (s, "[%d:%d][H1] app_wrk %u hc_index %u ts %d:%d",
+             req->c_thread_index, req->c_s_index, req->hr_pa_wrk_index,
+             req->hr_hc_index, ts->thread_index, ts->session_index);
+
+  return s;
+}
+
+static u8 *
+http1_format_req (u8 *s, va_list *args)
+{
+  u32 req_index = va_arg (*args, u32);
+  u32 thread_index = va_arg (*args, u32);
+  http_conn_t *hc = va_arg (*args, http_conn_t *);
+  u32 verbose = va_arg (*args, u32);
+  http_req_t *req;
+
+  req = http1_req_get (req_index, thread_index);
+
+  s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_http1_req, req, hc);
+  if (verbose)
     {
-      http_alloc_req (hc);
-      req = http_get_req (hc, 0);
-      req->app_session_handle = hc->h_pa_session_handle;
-      http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD);
+      s =
+       format (s, "%-" SESSION_CLI_STATE_LEN "U", format_http_conn_state, hc);
+      if (verbose > 1)
+       s = format (s, "\n");
     }
 
+  return s;
+}
+
+static void
+http1_app_tx_callback (http_conn_t *hc, u32 req_index,
+                      transport_send_params_t *sp)
+{
+  http_req_t *req;
+
+  req = http1_req_get (req_index, hc->c_thread_index);
+
   if (!http1_req_state_is_tx_valid (req))
     {
       /* Sometimes the server apps can send the response earlier
@@ -1645,7 +1771,7 @@ http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp)
        {
          clib_warning ("hc [%u]%x invalid tx state: http req state "
                        "'%U', session state '%U'",
-                       hc->c_thread_index, hc->h_hc_index,
+                       hc->c_thread_index, hc->hc_hc_index,
                        format_http_req_state, req->state,
                        format_http_conn_state, hc);
          http_io_as_drain_all (req);
@@ -1658,26 +1784,32 @@ http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp)
 }
 
 static void
-http1_app_rx_evt_callback (http_conn_t *hc)
+http1_app_rx_evt_callback (http_conn_t *hc, u32 req_index, u32 thread_index)
 {
   http_req_t *req;
 
-  req = http_get_req (hc, 0);
+  req = http1_req_get (req_index, thread_index);
 
   if (req->state == HTTP_REQ_STATE_TUNNEL)
     http1_req_state_tunnel_rx (hc, req, 0);
 }
 
 static void
-http1_app_close_callback (http_conn_t *hc)
+http1_app_close_callback (http_conn_t *hc, u32 req_index, u32 thread_index)
 {
   http_req_t *req;
 
-  req = http_get_req_if_valid (hc, 0);
+  req = http1_req_get_if_valid (req_index, thread_index);
+  if (!req)
+    {
+      HTTP_DBG (1, "req already deleted");
+      return;
+    }
   /* Nothing more to send, confirm close */
-  if (!req || !http_io_as_max_read (req))
+  if (!http_io_as_max_read (req))
     {
-      session_transport_closed_notify (&hc->connection);
+      HTTP_DBG (1, "nothing more to send, confirm close");
+      session_transport_closed_notify (&req->connection);
       http_disconnect_transport (hc);
     }
   else
@@ -1688,31 +1820,48 @@ http1_app_close_callback (http_conn_t *hc)
 }
 
 static void
-http1_app_reset_callback (http_conn_t *hc)
+http1_app_reset_callback (http_conn_t *hc, u32 req_index, u32 thread_index)
 {
-  session_transport_closed_notify (&hc->connection);
+  http_req_t *req;
+  req = http1_req_get (req_index, thread_index);
+  session_transport_closed_notify (&req->connection);
   http_disconnect_transport (hc);
 }
 
+static int
+http1_transport_connected_callback (http_conn_t *hc)
+{
+  http_req_t *req;
+
+  ASSERT (hc->flags & HTTP_CONN_F_NO_APP_SESSION);
+
+  req = http1_conn_alloc_req (hc);
+  http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD);
+  return http_conn_established (hc, req);
+}
+
 static void
 http1_transport_rx_callback (http_conn_t *hc)
 {
   http_req_t *req;
 
-  req = http_get_req_if_valid (hc, 0);
-  if (!req)
+  if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
     {
-      http_alloc_req (hc);
-      req = http_get_req (hc, 0);
-      req->app_session_handle = hc->h_pa_session_handle;
+      ASSERT (hc->flags & HTTP_CONN_F_IS_SERVER);
+      /* first request - create request ctx and notify app about new conn */
+      req = http1_conn_alloc_req (hc);
+      http_conn_accept_request (hc, req);
       http_req_state_change (req, HTTP_REQ_STATE_WAIT_TRANSPORT_METHOD);
+      hc->flags &= ~HTTP_CONN_F_NO_APP_SESSION;
     }
+  else
+    req = http1_conn_get_req (hc);
 
   if (!http1_req_state_is_rx_valid (req))
     {
       clib_warning ("hc [%u]%x invalid rx state: http req state "
                    "'%U', session state '%U'",
-                   hc->c_thread_index, hc->h_hc_index, format_http_req_state,
+                   hc->c_thread_index, hc->hc_hc_index, format_http_req_state,
                    req->state, format_http_conn_state, hc);
       http_io_ts_drain_all (hc);
       return;
@@ -1725,18 +1874,74 @@ http1_transport_rx_callback (http_conn_t *hc)
 static void
 http1_transport_close_callback (http_conn_t *hc)
 {
+  if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
+    return;
   /* Nothing more to rx, propagate to app */
   if (!http_io_ts_max_read (hc))
-    session_transport_closing_notify (&hc->connection);
+    {
+      http_req_t *req = http1_conn_get_req (hc);
+      session_transport_closing_notify (&req->connection);
+    }
+}
+
+static void
+http1_transport_reset_callback (http_conn_t *hc)
+{
+  if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
+    return;
+  http_req_t *req = http1_conn_get_req (hc);
+  session_transport_reset_notify (&req->connection);
+}
+
+static void
+http1_transport_conn_reschedule_callback (http_conn_t *hc)
+{
+  ASSERT (hc->flags & HTTP_CONN_F_HAS_REQUEST);
+  http_req_t *req = http1_conn_get_req (hc);
+  transport_connection_reschedule (&req->connection);
+}
+
+static void
+http1_conn_cleanup_callback (http_conn_t *hc)
+{
+  http_req_t *req;
+  if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
+    return;
+
+  req = http1_conn_get_req (hc);
+  session_transport_delete_notify (&req->connection);
+  http1_conn_free_req (hc);
+}
+
+static void
+http1_enable_callback (void)
+{
+  http1_main_t *h1m = &http1_main;
+  vlib_thread_main_t *vtm = vlib_get_thread_main ();
+  u32 num_threads;
+
+  num_threads = 1 /* main thread */ + vtm->n_threads;
+
+  vec_validate (h1m->req_pool, num_threads - 1);
 }
 
 const static http_engine_vft_t http1_engine = {
+  .name = "http1",
+  .hc_index_get_by_req_index = http1_hc_index_get_by_req_index,
+  .req_get_connection = http1_req_get_connection,
+  .format_req = http1_format_req,
   .app_tx_callback = http1_app_tx_callback,
   .app_rx_evt_callback = http1_app_rx_evt_callback,
   .app_close_callback = http1_app_close_callback,
   .app_reset_callback = http1_app_reset_callback,
+  .transport_connected_callback = http1_transport_connected_callback,
   .transport_rx_callback = http1_transport_rx_callback,
   .transport_close_callback = http1_transport_close_callback,
+  .transport_conn_reschedule_callback =
+    http1_transport_conn_reschedule_callback,
+  .transport_reset_callback = http1_transport_reset_callback,
+  .conn_cleanup_callback = http1_conn_cleanup_callback,
+  .enable_callback = http1_enable_callback,
 };
 
 static clib_error_t *
index 154a63d..ebec59a 100644 (file)
 
 #define HTTP_FIFO_THRESH (16 << 10)
 
-typedef u32 http_conn_handle_t;
+typedef union
+{
+  struct
+  {
+    u32 version : 3;
+    u32 conn_index : 29;
+  };
+  u32 as_u32;
+} http_conn_handle_t;
 
-typedef struct http_conn_id_
+STATIC_ASSERT (sizeof (http_conn_handle_t) == sizeof (u32), "must fit in u32");
+
+typedef union
 {
-  union
+  struct
   {
-    session_handle_t app_session_handle;
-    u32 parent_app_api_ctx;
+    u32 version : 3;
+    u32 req_index : 29;
   };
-  session_handle_t tc_session_handle;
-  u32 parent_app_wrk_index;
-} http_conn_id_t;
+  u32 as_u32;
+} http_req_handle_t;
 
-STATIC_ASSERT (sizeof (http_conn_id_t) <= TRANSPORT_CONN_ID_LEN,
-              "ctx id must be less than TRANSPORT_CONN_ID_LEN");
+STATIC_ASSERT (sizeof (http_req_handle_t) == sizeof (u32), "must fit in u32");
 
 #define foreach_http_conn_state                                               \
   _ (LISTEN, "LISTEN")                                                        \
@@ -80,10 +88,28 @@ typedef enum http_version_
   HTTP_VERSION_NA = 7,
 } http_version_t;
 
-typedef struct http_req_
+typedef struct http_req_id_
 {
-  /* in case of multiplexing we have app session for each stream */
   session_handle_t app_session_handle;
+  u32 parent_app_wrk_index;
+  u32 hc_index;
+} http_req_id_t;
+
+STATIC_ASSERT (sizeof (http_req_id_t) <= TRANSPORT_CONN_ID_LEN,
+              "ctx id must be less than TRANSPORT_CONN_ID_LEN");
+
+typedef struct http_req_
+{
+  union
+  {
+    transport_connection_t connection;
+    http_req_id_t c_http_req_id;
+  };
+#define hr_pa_wrk_index             c_http_req_id.parent_app_wrk_index
+#define hr_pa_session_handle c_http_req_id.app_session_handle
+#define hr_hc_index         c_http_req_id.hc_index
+#define hr_req_handle       connection.c_index
+
   u32 as_fifo_offset; /* for peek */
 
   http_req_state_t state; /* state-machine state */
@@ -142,7 +168,8 @@ typedef struct http_req_
   _ (HO_DONE, "ho-done")                                                      \
   _ (NO_APP_SESSION, "no-app-session")                                        \
   _ (PENDING_TIMER, "pending-timer")                                          \
-  _ (IS_SERVER, "is-server")
+  _ (IS_SERVER, "is-server")                                                  \
+  _ (HAS_REQUEST, "has-request")
 
 typedef enum http_conn_flags_bit_
 {
@@ -158,6 +185,20 @@ typedef enum http_conn_flags_
 #undef _
 } __clib_packed http_conn_flags_t;
 
+typedef struct http_conn_id_
+{
+  union
+  {
+    session_handle_t app_session_handle;
+    u32 parent_app_api_ctx;
+  };
+  session_handle_t tc_session_handle;
+  u32 parent_app_wrk_index;
+} http_conn_id_t;
+
+STATIC_ASSERT (sizeof (http_conn_id_t) <= TRANSPORT_CONN_ID_LEN,
+              "ctx id must be less than TRANSPORT_CONN_ID_LEN");
+
 typedef struct http_tc_
 {
   union
@@ -165,11 +206,11 @@ typedef struct http_tc_
     transport_connection_t connection;
     http_conn_id_t c_http_conn_id;
   };
-#define h_tc_session_handle c_http_conn_id.tc_session_handle
-#define h_pa_wrk_index     c_http_conn_id.parent_app_wrk_index
-#define h_pa_session_handle c_http_conn_id.app_session_handle
-#define h_pa_app_api_ctx    c_http_conn_id.parent_app_api_ctx
-#define h_hc_index         connection.c_index
+#define hc_tc_session_handle c_http_conn_id.tc_session_handle
+#define hc_pa_wrk_index             c_http_conn_id.parent_app_wrk_index
+#define hc_pa_session_handle c_http_conn_id.app_session_handle
+#define hc_pa_app_api_ctx    c_http_conn_id.parent_app_api_ctx
+#define hc_hc_index         connection.c_index
 
   http_version_t version;
   http_conn_state_t state;
@@ -180,7 +221,7 @@ typedef struct http_tc_
   http_conn_flags_t flags;
   http_udp_tunnel_mode_t udp_tunnel_mode;
 
-  http_req_t *req_pool; /* multiplexing => request per stream */
+  void *opaque; /* version specific data */
 } http_conn_t;
 
 typedef struct http_worker_
@@ -219,12 +260,27 @@ typedef struct http_main_
 
 typedef struct http_engine_vft_
 {
-  void (*app_tx_callback) (http_conn_t *hc, transport_send_params_t *sp);
-  void (*app_rx_evt_callback) (http_conn_t *hc);
-  void (*app_close_callback) (http_conn_t *hc);
-  void (*app_reset_callback) (http_conn_t *hc);
+  const char *name;
+  u32 (*hc_index_get_by_req_index) (u32 req_index, u32 thread_index);
+  transport_connection_t *(*req_get_connection) (u32 req_index,
+                                                u32 thread_index);
+  u8 *(*format_req) (u8 *s, va_list *args);
+  void (*app_tx_callback) (http_conn_t *hc, u32 req_index,
+                          transport_send_params_t *sp);
+  void (*app_rx_evt_callback) (http_conn_t *hc, u32 req_index,
+                              u32 thread_index);
+  void (*app_close_callback) (http_conn_t *hc, u32 req_index,
+                             u32 thread_index);
+  void (*app_reset_callback) (http_conn_t *hc, u32 req_index,
+                             u32 thread_index);
+  int (*transport_connected_callback) (http_conn_t *hc);
   void (*transport_rx_callback) (http_conn_t *hc);
   void (*transport_close_callback) (http_conn_t *hc);
+  void (*transport_reset_callback) (http_conn_t *hc);
+  void (*transport_conn_reschedule_callback) (http_conn_t *hc);
+  void (*conn_cleanup_callback) (http_conn_t *hc);
+  void (*enable_callback) (void);                          /* optional */
+  uword (*unformat_cfg_callback) (unformat_input_t *input); /* optional */
 } http_engine_vft_t;
 
 void http_register_engine (const http_engine_vft_t *vft,
@@ -300,14 +356,14 @@ http_status_code_t http_sc_by_u16 (u16 status_code);
 /**
  * Read header list sent by app.
  *
- * @param hc  HTTP connection.
+ * @param req HTTP request.
  * @param msg HTTP msg sent by app.
  *
  * @return Pointer to the header list.
  *
  * @note For immediate processing, not for buffering.
  */
-u8 *http_get_app_header_list (http_conn_t *hc, http_msg_t *msg);
+u8 *http_get_app_header_list (http_req_t *req, http_msg_t *msg);
 
 /**
  * Get pre-allocated TX buffer/vector.
@@ -334,7 +390,7 @@ u8 *http_get_rx_buf (http_conn_t *hc);
 /**
  * Read request target path sent by app.
  *
- * @param hc  HTTP connection.
+ * @param req HTTP request.
  * @param msg HTTP msg sent by app.
  *
  * @return Pointer to the target path.
@@ -353,69 +409,6 @@ u8 *http_get_app_target (http_req_t *req, http_msg_t *msg);
  */
 void http_req_tx_buffer_init (http_req_t *req, http_msg_t *msg);
 
-/**
- * Allocate new request within given HTTP connection.
- *
- * @param hc  HTTP connection.
- *
- * @return Request index in per-connection pool.
- */
-always_inline u32
-http_alloc_req (http_conn_t *hc)
-{
-  http_req_t *req;
-  pool_get_zero (hc->req_pool, req);
-  req->app_session_handle = SESSION_INVALID_HANDLE;
-  return (req - hc->req_pool);
-}
-
-/**
- * Get request in per-connection pool.
- *
- * @param hc        HTTP connection.
- * @param req_index Request index.
- *
- * @return Pointer to the request data.
- */
-always_inline http_req_t *
-http_get_req (http_conn_t *hc, u32 req_index)
-{
-  return pool_elt_at_index (hc->req_pool, req_index);
-}
-
-/**
- * Get request in per-connection pool if valid.
- *
- * @param hc        HTTP connection.
- * @param req_index Request index.
- *
- * @return Pointer to the request data or @c 0 if not valid.
- */
-always_inline http_req_t *
-http_get_req_if_valid (http_conn_t *hc, u32 req_index)
-{
-  if (pool_is_free_index (hc->req_pool, req_index))
-    return 0;
-  return pool_elt_at_index (hc->req_pool, req_index);
-}
-
-/**
- * Free request in per-connection pool.
- *
- * @param hc  HTTP connection.
- * @param req Pointer to the request.
- */
-always_inline void
-http_req_free (http_conn_t *hc, http_req_t *req)
-{
-  vec_free (req->headers);
-  vec_free (req->target);
-  http_buffer_free (&req->tx_buf);
-  if (CLIB_DEBUG)
-    memset (req, 0xba, sizeof (*req));
-  pool_put (hc->req_pool, req);
-}
-
 /**
  * Change state of given HTTP request.
  *
@@ -442,7 +435,7 @@ http_app_worker_rx_notify (http_req_t *req)
   session_t *as;
   app_worker_t *app_wrk;
 
-  as = session_get_from_handle (req->app_session_handle);
+  as = session_get_from_handle (req->hr_pa_session_handle);
   app_wrk = app_worker_get_if_valid (as->app_wrk_index);
   if (app_wrk)
     app_worker_rx_notify (app_wrk, as);
@@ -459,7 +452,7 @@ always_inline transport_proto_t
 http_get_transport_proto (http_conn_t *hc)
 {
   return session_get_transport_proto (
-    session_get_from_handle (hc->h_tc_session_handle));
+    session_get_from_handle (hc->hc_tc_session_handle));
 }
 
 /**
@@ -474,7 +467,7 @@ http_get_app_msg (http_req_t *req, http_msg_t *msg)
   session_t *as;
   int rv;
 
-  as = session_get_from_handle (req->app_session_handle);
+  as = session_get_from_handle (req->hr_pa_session_handle);
   rv = svm_fifo_dequeue (as->tx_fifo, sizeof (*msg), (u8 *) msg);
   ASSERT (rv == sizeof (*msg));
 }
@@ -484,21 +477,21 @@ http_get_app_msg (http_req_t *req, http_msg_t *msg)
 always_inline void
 http_io_as_want_deq_ntf (http_req_t *req)
 {
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   svm_fifo_add_want_deq_ntf (as->rx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
 }
 
 always_inline u32
 http_io_as_max_write (http_req_t *req)
 {
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   return svm_fifo_max_enqueue_prod (as->rx_fifo);
 }
 
 always_inline u32
 http_io_as_max_read (http_req_t *req)
 {
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   return svm_fifo_max_dequeue_cons (as->tx_fifo);
 }
 
@@ -507,7 +500,7 @@ http_io_as_write_segs (http_req_t *req, const svm_fifo_seg_t segs[],
                       u32 n_segs)
 {
   int n_written;
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   n_written = svm_fifo_enqueue_segments (as->rx_fifo, segs, n_segs, 0);
   ASSERT (n_written > 0);
   return (u32) n_written;
@@ -517,7 +510,7 @@ always_inline u32
 http_io_as_read (http_req_t *req, u8 *buf, u32 len, u8 peek)
 {
   int n_read;
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
 
   if (peek)
     {
@@ -537,7 +530,7 @@ http_io_as_read_segs (http_req_t *req, svm_fifo_seg_t *segs, u32 *n_segs,
                      u32 max_bytes)
 {
   int n_read;
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   n_read = svm_fifo_segments (as->tx_fifo, 0, segs, n_segs, max_bytes);
   ASSERT (n_read > 0);
 }
@@ -545,7 +538,7 @@ http_io_as_read_segs (http_req_t *req, svm_fifo_seg_t *segs, u32 *n_segs,
 always_inline void
 http_io_as_drain (http_req_t *req, u32 len)
 {
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   svm_fifo_dequeue_drop (as->tx_fifo, len);
   req->as_fifo_offset = 0;
 }
@@ -553,7 +546,7 @@ http_io_as_drain (http_req_t *req, u32 len)
 always_inline void
 http_io_as_drain_all (http_req_t *req)
 {
-  session_t *as = session_get_from_handle (req->app_session_handle);
+  session_t *as = session_get_from_handle (req->hr_pa_session_handle);
   svm_fifo_dequeue_drop_all (as->tx_fifo);
   req->as_fifo_offset = 0;
 }
@@ -563,14 +556,14 @@ http_io_as_drain_all (http_req_t *req)
 always_inline u32
 http_io_ts_max_read (http_conn_t *hc)
 {
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   return svm_fifo_max_dequeue_cons (ts->rx_fifo);
 }
 
 always_inline u32
 http_io_ts_max_write (http_conn_t *hc, transport_send_params_t *sp)
 {
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   return clib_min (svm_fifo_max_enqueue_prod (ts->tx_fifo),
                   sp->max_burst_size);
 }
@@ -579,7 +572,7 @@ always_inline u32
 http_io_ts_read (http_conn_t *hc, u8 *buf, u32 len, u8 peek)
 {
   int n_read;
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
 
   if (peek)
     {
@@ -598,7 +591,7 @@ http_io_ts_read_segs (http_conn_t *hc, svm_fifo_seg_t *segs, u32 *n_segs,
                      u32 max_bytes)
 {
   int n_read;
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   n_read = svm_fifo_segments (ts->rx_fifo, 0, segs, n_segs, max_bytes);
   ASSERT (n_read > 0);
 }
@@ -606,21 +599,21 @@ http_io_ts_read_segs (http_conn_t *hc, svm_fifo_seg_t *segs, u32 *n_segs,
 always_inline void
 http_io_ts_drain (http_conn_t *hc, u32 len)
 {
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   svm_fifo_dequeue_drop (ts->rx_fifo, len);
 }
 
 always_inline void
 http_io_ts_drain_all (http_conn_t *hc)
 {
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   svm_fifo_dequeue_drop_all (ts->rx_fifo);
 }
 
 always_inline void
 http_io_ts_after_read (http_conn_t *hc, u8 clear_evt)
 {
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   if (clear_evt)
     {
       if (svm_fifo_is_empty_cons (ts->rx_fifo))
@@ -629,7 +622,7 @@ http_io_ts_after_read (http_conn_t *hc, u8 clear_evt)
   else
     {
       if (svm_fifo_max_dequeue_cons (ts->rx_fifo))
-       session_program_rx_io_evt (hc->h_tc_session_handle);
+       session_program_rx_io_evt (hc->hc_tc_session_handle);
     }
 }
 
@@ -638,7 +631,7 @@ http_io_ts_write (http_conn_t *hc, u8 *data, u32 len,
                  transport_send_params_t *sp)
 {
   int n_written;
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
 
   n_written = svm_fifo_enqueue (ts->tx_fifo, len, data);
   ASSERT (n_written == len);
@@ -655,7 +648,7 @@ http_io_ts_write_segs (http_conn_t *hc, const svm_fifo_seg_t segs[],
                       u32 n_segs, transport_send_params_t *sp)
 {
   int n_written;
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
   n_written = svm_fifo_enqueue_segments (ts->tx_fifo, segs, n_segs, 0);
   ASSERT (n_written > 0);
   sp->bytes_dequeued += n_written;
@@ -667,7 +660,7 @@ always_inline void
 http_io_ts_after_write (http_conn_t *hc, transport_send_params_t *sp, u8 flush,
                        u8 written)
 {
-  session_t *ts = session_get_from_handle (hc->h_tc_session_handle);
+  session_t *ts = session_get_from_handle (hc->hc_tc_session_handle);
 
   if (!flush)
     {
@@ -690,4 +683,97 @@ http_io_ts_after_write (http_conn_t *hc, transport_send_params_t *sp, u8 flush,
     }
 }
 
+always_inline int
+http_conn_accept_request (http_conn_t *hc, http_req_t *req)
+{
+  session_t *as, *asl;
+  app_worker_t *app_wrk;
+  int rv;
+
+  HTTP_DBG (1, "hc [%u]%x req %x", hc->hc_hc_index, hc->c_thread_index,
+           req->hr_req_index);
+
+  /* allocate app session and initialize */
+  as = session_alloc (hc->c_thread_index);
+  HTTP_DBG (1, "allocated session 0x%lx", session_handle (as));
+  req->c_s_index = as->session_index;
+  as->app_wrk_index = hc->hc_pa_wrk_index;
+  as->connection_index = req->hr_req_handle;
+  as->session_state = SESSION_STATE_ACCEPTING;
+  asl = listen_session_get_from_handle (hc->hc_pa_session_handle);
+  as->session_type = asl->session_type;
+  as->listener_handle = hc->hc_pa_session_handle;
+
+  /* init session fifos and notify app */
+  if ((rv = app_worker_init_accepted (as)))
+    {
+      HTTP_DBG (1, "failed to allocate fifos");
+      req->hr_pa_session_handle = SESSION_INVALID_HANDLE;
+      session_free (as);
+      hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
+      return rv;
+    }
+
+  req->hr_pa_session_handle = session_handle (as);
+  req->hr_pa_wrk_index = as->app_wrk_index;
+
+  app_wrk = app_worker_get (as->app_wrk_index);
+
+  if ((rv = app_worker_accept_notify (app_wrk, as)))
+    {
+      HTTP_DBG (1, "app accept returned");
+      req->hr_pa_session_handle = SESSION_INVALID_HANDLE;
+      session_free (as);
+      hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
+      return rv;
+    }
+
+  return 0;
+}
+
+always_inline int
+http_conn_established (http_conn_t *hc, http_req_t *req)
+{
+  session_t *as;
+  app_worker_t *app_wrk;
+  session_t *ts;
+  int rv;
+
+  /* allocate app session and initialize */
+  as = session_alloc (hc->c_thread_index);
+  HTTP_DBG (1, "allocated session 0x%lx", session_handle (as));
+  req->c_s_index = as->session_index;
+  as->app_wrk_index = hc->hc_pa_wrk_index;
+  as->connection_index = req->hr_req_handle;
+  as->session_state = SESSION_STATE_READY;
+  as->opaque = hc->hc_pa_app_api_ctx;
+  ts = session_get_from_handle (hc->hc_tc_session_handle);
+  as->session_type = session_type_from_proto_and_ip (
+    TRANSPORT_PROTO_HTTP, session_type_is_ip4 (ts->session_type));
+
+  /* init session fifos and notify app */
+  app_wrk = app_worker_get_if_valid (hc->hc_pa_wrk_index);
+  if (!app_wrk)
+    {
+      HTTP_DBG (1, "no app worker");
+      hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
+      return -1;
+    }
+
+  if ((rv = app_worker_init_connected (app_wrk, as)))
+    {
+      HTTP_DBG (1, "failed to allocate fifos");
+      session_free (as);
+      hc->flags |= HTTP_CONN_F_NO_APP_SESSION;
+      return rv;
+    }
+
+  app_worker_connect_notify (app_wrk, as, 0, hc->hc_pa_app_api_ctx);
+
+  req->hr_pa_session_handle = session_handle (as);
+  req->hr_pa_wrk_index = as->app_wrk_index;
+
+  return 0;
+}
+
 #endif /* SRC_PLUGINS_HTTP_HTTP_PRIVATE_H_ */
index 50f634c..5ce4203 100644 (file)
@@ -45,8 +45,8 @@ http_conn_timer_start (http_conn_t *hc)
   u32 hs_handle;
 
   ASSERT (hc->timer_handle == HTTP_TIMER_HANDLE_INVALID);
-  ASSERT (hc->h_hc_index <= 0x00FFFFFF);
-  hs_handle = hc->c_thread_index << 24 | hc->h_hc_index;
+  ASSERT (hc->hc_hc_index <= 0x00FFFFFF);
+  hs_handle = hc->c_thread_index << 24 | hc->hc_hc_index;
 
   clib_spinlock_lock (&twc->tw_lock);
   hc->timer_handle =
@@ -80,8 +80,8 @@ http_conn_timer_update (http_conn_t *hc)
     tw_timer_update_2t_1w_2048sl (&twc->tw, hc->timer_handle, hc->timeout);
   else
     {
-      ASSERT (hc->h_hc_index <= 0x00FFFFFF);
-      hs_handle = hc->c_thread_index << 24 | hc->h_hc_index;
+      ASSERT (hc->hc_hc_index <= 0x00FFFFFF);
+      hs_handle = hc->c_thread_index << 24 | hc->hc_hc_index;
       hc->timer_handle =
        tw_timer_start_2t_1w_2048sl (&twc->tw, hs_handle, 0, hc->timeout);
     }