http_static: add support for async tx from handlers 73/35173/6
authorFlorin Coras <[email protected]>
Tue, 1 Feb 2022 21:17:13 +0000 (13:17 -0800)
committerDamjan Marion <[email protected]>
Wed, 2 Feb 2022 10:35:23 +0000 (10:35 +0000)
URL handlers can send data asynchronously if needed.

Type: improvement

Signed-off-by: Florin Coras <[email protected]>
Change-Id: I89eae690cb26543479c7659b5dc46604cbb22eba

src/plugins/builtinurl/builtins.c
src/plugins/http_static/builtinurl/json_urls.c
src/plugins/http_static/http_static.c
src/plugins/http_static/http_static.h
src/plugins/http_static/static_server.c
src/plugins/mactime/builtins.c

index 4ebcd64..14b68ce 100644 (file)
@@ -18,8 +18,8 @@
 #include <http_static/http_static.h>
 #include <vpp/app/version.h>
 
-int
-handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs)
+hss_url_handler_rc_t
+handle_get_version (hss_url_handler_args_t *args)
 {
   u8 *s = 0;
 
@@ -28,11 +28,10 @@ handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs)
   s = format (s, "   \"version\": \"%s\",", VPP_BUILD_VER);
   s = format (s, "   \"build_date\": \"%s\"}}\r\n", VPP_BUILD_DATE);
 
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
-  return 0;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
+  return HSS_URL_HANDLER_OK;
 }
 
 void
@@ -62,9 +61,8 @@ trim_path_from_request (u8 * s, char *path)
     }
 }
 
-int
-handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
-                           hss_session_t *hs)
+hss_url_handler_rc_t
+handle_get_interface_stats (hss_url_handler_args_t *args)
 {
   u8 *s = 0, *stats = 0;
   uword *p;
@@ -80,16 +78,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
   vnet_interface_main_t *im = &vnm->interface_main;
 
   /* Get stats for a single interface via http POST */
-  if (reqtype == HTTP_REQ_POST)
+  if (args->reqtype == HTTP_REQ_POST)
     {
-      trim_path_from_request (request, "interface_stats.json");
+      trim_path_from_request (args->request, "interface_stats.json");
 
       /* Find the sw_if_index */
-      p = hash_get (im->hw_interface_by_name, request);
+      p = hash_get (im->hw_interface_by_name, args->request);
       if (!p)
        {
          s = format (s, "{\"interface_stats\": {[\n");
-         s = format (s, "   \"name\": \"%s\",", request);
+         s = format (s, "   \"name\": \"%s\",", args->request);
          s = format (s, "   \"error\": \"%s\"", "UnknownInterface");
          s = format (s, "]}\n");
          goto out;
@@ -132,18 +130,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
   s = format (s, "]}\n");
 
 out:
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
   vec_free (sw_if_indices);
   vec_free (stats);
-  return 0;
+  return HSS_URL_HANDLER_OK;
 }
 
-int
-handle_get_interface_list (http_req_method_t reqtype, u8 *request,
-                          hss_session_t *hs)
+hss_url_handler_rc_t
+handle_get_interface_list (hss_url_handler_args_t *args)
 {
   u8 *s = 0;
   int i;
@@ -176,11 +172,10 @@ handle_get_interface_list (http_req_method_t reqtype, u8 *request,
   s = format (s, "]}\n");
   vec_free (hw_if_indices);
 
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
-  return 0;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
+  return HSS_URL_HANDLER_OK;
 }
 
 void
index ccd70fb..0d83d39 100644 (file)
@@ -16,8 +16,8 @@
 #include <http_static/http_static.h>
 #include <vpp/app/version.h>
 
-int
-handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs)
+hss_url_handler_rc_t
+handle_get_version (hss_url_handler_args_t *args)
 {
   u8 *s = 0;
 
@@ -25,11 +25,10 @@ handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs)
   s = format (s, "   \"version\": \"%s\",", VPP_BUILD_VER);
   s = format (s, "   \"build_date\": \"%s\"}}\r\n", VPP_BUILD_DATE);
 
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
-  return 0;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
+  return HSS_URL_HANDLER_OK;
 }
 
 void
@@ -59,9 +58,8 @@ trim_path_from_request (u8 *s, char *path)
     }
 }
 
-int
-handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
-                           hss_session_t *hs)
+hss_url_handler_rc_t
+handle_get_interface_stats (hss_url_handler_args_t *args)
 {
   u8 *s = 0, *stats = 0;
   uword *p;
@@ -77,16 +75,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
   vnet_interface_main_t *im = &vnm->interface_main;
 
   /* Get stats for a single interface via http POST */
-  if (reqtype == HTTP_REQ_POST)
+  if (args->reqtype == HTTP_REQ_POST)
     {
-      trim_path_from_request (request, "interface_stats.json");
+      trim_path_from_request (args->request, "interface_stats.json");
 
       /* Find the sw_if_index */
-      p = hash_get (im->hw_interface_by_name, request);
+      p = hash_get (im->hw_interface_by_name, args->request);
       if (!p)
        {
          s = format (s, "{\"interface_stats\": {[\n");
-         s = format (s, "   \"name\": \"%s\",", request);
+         s = format (s, "   \"name\": \"%s\",", args->request);
          s = format (s, "   \"error\": \"%s\"", "UnknownInterface");
          s = format (s, "]}\n");
          goto out;
@@ -127,18 +125,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
   s = format (s, "]}\n");
 
 out:
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
   vec_free (sw_if_indices);
   vec_free (stats);
-  return 0;
+  return HSS_URL_HANDLER_OK;
 }
 
-int
-handle_get_interface_list (http_req_method_t reqtype, u8 *request,
-                          hss_session_t *hs)
+hss_url_handler_rc_t
+handle_get_interface_list (hss_url_handler_args_t *args)
 {
   u8 *s = 0;
   int i;
@@ -169,11 +165,10 @@ handle_get_interface_list (http_req_method_t reqtype, u8 *request,
   s = format (s, "]}\n");
   vec_free (hw_if_indices);
 
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
-  return 0;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
+  return HSS_URL_HANDLER_OK;
 }
 
 void
index b8d6931..4afe422 100644 (file)
@@ -33,7 +33,7 @@
 #include <vlibapi/api_helper_macros.h>
 
 __clib_export void
-hss_register_url_handler (hss_url_handler_t fp, const char *url,
+hss_register_url_handler (hss_url_handler_fn fp, const char *url,
                          http_req_method_t request_type)
 {
   hss_main_t *hsm = &hss_main;
index 05d6ee0..d3fa29b 100644 (file)
@@ -40,8 +40,10 @@ typedef struct
   session_handle_t vpp_session_handle;
   /** Fully-resolved file path */
   u8 *path;
-  /** File data, a vector */
+  /** Data to send */
   u8 *data;
+  /** Data length */
+  u32 data_len;
   /** Current data send offset */
   u32 data_offset;
   /** Need to free data in detach_cache_entry */
@@ -50,6 +52,21 @@ typedef struct
   u32 cache_pool_index;
 } hss_session_t;
 
+typedef struct hss_session_handle_
+{
+  union
+  {
+    struct
+    {
+      u32 session_index;
+      u32 thread_index;
+    };
+    u64 as_u64;
+  };
+} hss_session_handle_t;
+
+STATIC_ASSERT_SIZEOF (hss_session_handle_t, sizeof (u64));
+
 /** \brief In-memory file data cache entry
  */
 typedef struct
@@ -67,7 +84,40 @@ typedef struct
   int inuse;
 } hss_cache_entry_t;
 
-typedef int (*hss_url_handler_t) (http_req_method_t, u8 *, hss_session_t *);
+typedef struct hss_url_handler_args_
+{
+  hss_session_handle_t sh;
+
+  union
+  {
+    /* Request args */
+    struct
+    {
+      u8 *request;
+      http_req_method_t reqtype;
+    };
+
+    /* Reply args */
+    struct
+    {
+      u8 *data;
+      uword data_len;
+      u8 free_vec_data;
+      http_status_code_t sc;
+    };
+  };
+} hss_url_handler_args_t;
+
+typedef enum hss_url_handler_rc_
+{
+  HSS_URL_HANDLER_OK,
+  HSS_URL_HANDLER_ERROR,
+  HSS_URL_HANDLER_ASYNC,
+} hss_url_handler_rc_t;
+
+typedef hss_url_handler_rc_t (*hss_url_handler_fn) (hss_url_handler_args_t *);
+typedef void (*hss_register_url_fn) (hss_url_handler_fn, char *, int);
+typedef void (*hss_session_send_fn) (hss_url_handler_args_t *args);
 
 /** \brief Main data structure
  */
@@ -139,8 +189,9 @@ int hss_create (vlib_main_t *vm);
 /**
  * Register a GET or POST URL handler
  */
-void hss_register_url_handler (hss_url_handler_t fp, const char *url,
+void hss_register_url_handler (hss_url_handler_fn fp, const char *url,
                               http_req_method_t type);
+void hss_session_send_data (hss_url_handler_args_t *args);
 void hss_builtinurl_json_handlers_init (void);
 
 #endif /* __included_http_static_h__ */
index a78b5fe..a9b3fdb 100644 (file)
@@ -257,9 +257,9 @@ start_send_data (hss_session_t *hs, http_status_code_t status)
   msg.type = HTTP_MSG_REPLY;
   msg.code = status;
   msg.content_type = HTTP_CONTENT_TEXT_HTML;
-  msg.data.len = vec_len (hs->data);
+  msg.data.len = hs->data_len;
 
-  if (vec_len (hs->data) > hss_main.use_ptr_thresh)
+  if (hs->data_len > hss_main.use_ptr_thresh)
     {
       msg.data.type = HTTP_MSG_DATA_PTR;
       rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
@@ -280,9 +280,9 @@ start_send_data (hss_session_t *hs, http_status_code_t status)
   if (!msg.data.len)
     goto done;
 
-  rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (hs->data), hs->data);
+  rv = svm_fifo_enqueue (ts->tx_fifo, hs->data_len, hs->data);
 
-  if (rv != vec_len (hs->data))
+  if (rv != hs->data_len)
     {
       hs->data_offset = rv;
       svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF);
@@ -294,12 +294,25 @@ done:
     session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
 }
 
+__clib_export void
+hss_session_send_data (hss_url_handler_args_t *args)
+{
+  hss_session_t *hs;
+
+  hs = hss_session_get (args->sh.thread_index, args->sh.session_index);
+  hs->data = args->data;
+  hs->data_len = args->data_len;
+  hs->free_data = args->free_vec_data;
+  start_send_data (hs, args->sc);
+}
+
 static int
 try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
-                u8 *request, http_status_code_t *sc)
+                u8 *request)
 {
+  http_status_code_t sc = HTTP_STATUS_OK;
+  hss_url_handler_args_t args = {};
   uword *p, *url_table;
-  hss_url_handler_t fp;
   int rv;
 
   if (!hsm->enable_url_handlers)
@@ -313,24 +326,45 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
   if (!p)
     return -1;
 
+  hs->path = 0;
+  hs->data_offset = 0;
+  hs->cache_pool_index = ~0;
+
   if (hsm->debug_level > 0)
     clib_warning ("%s '%s'", (rt == HTTP_REQ_GET) ? "GET" : "POST", request);
 
-  fp = (hss_url_handler_t) p[0];
-  hs->path = 0;
-  rv = fp (rt, request, hs);
-  if (rv)
+  args.reqtype = rt;
+  args.request = request;
+  args.sh.thread_index = hs->thread_index;
+  args.sh.session_index = hs->session_index;
+
+  rv = ((hss_url_handler_fn) p[0]) (&args);
+
+  /* Wait for data from handler */
+  if (rv == HSS_URL_HANDLER_ASYNC)
+    return 0;
+
+  if (rv == HSS_URL_HANDLER_ERROR)
     {
       clib_warning ("builtin handler %llx hit on %s '%s' but failed!", p[0],
                    (rt == HTTP_REQ_GET) ? "GET" : "POST", request);
-      *sc = HTTP_STATUS_NOT_FOUND;
+      sc = HTTP_STATUS_NOT_FOUND;
     }
 
+  hs->data = args.data;
+  hs->data_len = args.data_len;
+  hs->free_data = args.free_vec_data;
+
+  start_send_data (hs, sc);
+
+  if (!hs->data)
+    hss_session_disconnect_transport (hs);
+
   return 0;
 }
 
 static int
-find_data (hss_session_t *hs, http_req_method_t rt, u8 *request)
+handle_request (hss_session_t *hs, http_req_method_t rt, u8 *request)
 {
   http_status_code_t sc = HTTP_STATUS_OK;
   hss_main_t *hsm = &hss_main;
@@ -338,8 +372,8 @@ find_data (hss_session_t *hs, http_req_method_t rt, u8 *request)
   clib_error_t *error;
   u8 *path;
 
-  if (!try_url_handler (hsm, hs, rt, request, &sc))
-    goto done;
+  if (!try_url_handler (hsm, hs, rt, request))
+    return 0;
 
   /*
    * Construct the file to open
@@ -541,6 +575,10 @@ find_data (hss_session_t *hs, http_req_method_t rt, u8 *request)
 
 done:
 
+  start_send_data (hs, sc);
+  if (!hs->data)
+    hss_session_disconnect_transport (hs);
+
   return sc;
 }
 
@@ -551,7 +589,6 @@ hss_ts_rx_callback (session_t *ts)
   u8 *request = 0;
   http_msg_t msg;
   int rv;
-  http_status_code_t sc;
 
   hs = hss_session_get (ts->thread_index, ts->opaque);
 
@@ -573,12 +610,9 @@ hss_ts_rx_callback (session_t *ts)
   ASSERT (rv == msg.data.len);
 
   /* Find and send data */
-  sc = find_data (hs, msg.method_type, request);
-  start_send_data (hs, sc);
+  handle_request (hs, msg.method_type, request);
 
   vec_free (request);
-  if (!hs->data)
-    hss_session_disconnect_transport (hs);
 
   return 0;
 }
@@ -594,7 +628,7 @@ hss_ts_tx_callback (session_t *ts)
   if (!hs || !hs->data)
     return 0;
 
-  to_send = vec_len (hs->data) - hs->data_offset;
+  to_send = hs->data_len - hs->data_offset;
   rv = svm_fifo_enqueue (ts->tx_fifo, to_send, hs->data + hs->data_offset);
 
   if (rv <= 0)
@@ -982,7 +1016,7 @@ format_hss_session (u8 *s, va_list *args)
   int __clib_unused verbose = va_arg (*args, int);
 
   s = format (s, "\n path %s, data length %u, data_offset %u",
-             hs->path ? hs->path : (u8 *) "[none]", vec_len (hs->data),
+             hs->path ? hs->path : (u8 *) "[none]", hs->data_len,
              hs->data_offset);
   return s;
 }
index d039f7b..c487d03 100644 (file)
@@ -14,8 +14,8 @@ mactime_ip_neighbor_copy (index_t ipni, void *ctx)
   return (WALK_CONTINUE);
 }
 
-static int
-handle_get_mactime (http_req_method_t reqtype, u8 *request, hss_session_t *hs)
+static hss_url_handler_rc_t
+handle_get_mactime (hss_url_handler_args_t *args)
 {
   mactime_main_t *mm = &mactime_main;
   mactime_device_t *dp;
@@ -145,17 +145,16 @@ handle_get_mactime (http_req_method_t reqtype, u8 *request, hss_session_t *hs)
   vec_free (macstring);
   vec_free (pool_indices);
 
-  hs->data = s;
-  hs->data_offset = 0;
-  hs->cache_pool_index = ~0;
-  hs->free_data = 1;
-  return 0;
+  args->data = s;
+  args->data_len = vec_len (s);
+  args->free_vec_data = 1;
+  return HSS_URL_HANDLER_OK;
 }
 
 void
 mactime_url_init (vlib_main_t * vm)
 {
-  void (*fp) (void *, char *, int);
+  hss_register_url_fn fp;
 
   /* Look up the builtin URL registration handler */
   fp = vlib_get_plugin_symbol ("http_static_plugin.so",