http_static: incorporate builtinurl plugin 43/35143/6
authorFlorin Coras <fcoras@cisco.com>
Fri, 28 Jan 2022 23:26:39 +0000 (15:26 -0800)
committerDamjan Marion <dmarion@me.com>
Sun, 30 Jan 2022 14:44:40 +0000 (14:44 +0000)
External handlers can still be registered via hss_register_url_handler
but url handlers must be enabled when server is created.

builtinurl plugin to be removed in a future patch

Type: refactor

Signed-off-by: Florin Coras <fcoras@cisco.com>
Change-Id: I94e103d908b9e118c7927b997a21ce3f67809889

src/plugins/http_static/CMakeLists.txt
src/plugins/http_static/FEATURE.yaml
src/plugins/http_static/builtinurl/json_urls.c [new file with mode: 0644]
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 f9ccb15..cf9e41e 100644 (file)
@@ -17,6 +17,7 @@ add_vpp_plugin(http_static
   http_static.c
   static_server.c
   http_static.h
+  builtinurl/json_urls.c
 
   API_FILES
   http_static.api
index d40855f..ff4e147 100644 (file)
@@ -1,10 +1,18 @@
 ---
-name: Static http https server
-maintainer: Dave Barach <dave@barachs.net>
+name: Static HTTP(S) Server
+maintainer:
+ - Dave Barach <dave@barachs.net>
+ - Florin Coras <fcoras@cisco.com>
 features:
-  - An extensible static http/https server with caching
-description: "A simple caching static http / https server
-              A built-in vpp host stack application.
-              Supports HTTP GET and HTTP POST methods."
+  - HTTP GET/POST handling
+  - LRU file caching
+  - pluggable URL handlers
+  - builtin json URL handles:
+    - version.json - vpp version info
+    - interface_list.json - list of interfaces
+    - interface_stats - single interface via HTTP POST
+    - interface_stats - all intfcs via HTTP GET."
+description: "Static HTTP(S) server implemented as a
+                                         built-in vpp host stack application. "
 state: production
 properties: [API, CLI, MULTITHREAD]
diff --git a/src/plugins/http_static/builtinurl/json_urls.c b/src/plugins/http_static/builtinurl/json_urls.c
new file mode 100644 (file)
index 0000000..ccd70fb
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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)
+{
+  u8 *s = 0;
+
+  s = format (s, "{\"vpp_details\": {");
+  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;
+}
+
+void
+trim_path_from_request (u8 *s, char *path)
+{
+  u8 *cp;
+  int trim_length = strlen (path) + 1 /* remove '?' */;
+
+  /* Get rid of the path and question-mark */
+  vec_delete (s, trim_length, 0);
+
+  /* Tail trim irrelevant browser info */
+  cp = s;
+  while ((cp - s) < vec_len (s))
+    {
+      if (*cp == ' ')
+       {
+         /*
+          * Makes request a vector which happens to look
+          * like a c-string.
+          */
+         *cp = 0;
+         _vec_len (s) = cp - s;
+         break;
+       }
+      cp++;
+    }
+}
+
+int
+handle_get_interface_stats (http_req_method_t reqtype, u8 *request,
+                           hss_session_t *hs)
+{
+  u8 *s = 0, *stats = 0;
+  uword *p;
+  u32 *sw_if_indices = 0;
+  vnet_hw_interface_t *hi;
+  vnet_sw_interface_t *si;
+  char *q = "\"";
+  int i;
+  int need_comma = 0;
+  u8 *format_vnet_sw_interface_cntrs (u8 * s, vnet_interface_main_t * im,
+                                     vnet_sw_interface_t * si, int json);
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_interface_main_t *im = &vnm->interface_main;
+
+  /* Get stats for a single interface via http POST */
+  if (reqtype == HTTP_REQ_POST)
+    {
+      trim_path_from_request (request, "interface_stats.json");
+
+      /* Find the sw_if_index */
+      p = hash_get (im->hw_interface_by_name, request);
+      if (!p)
+       {
+         s = format (s, "{\"interface_stats\": {[\n");
+         s = format (s, "   \"name\": \"%s\",", request);
+         s = format (s, "   \"error\": \"%s\"", "UnknownInterface");
+         s = format (s, "]}\n");
+         goto out;
+       }
+
+      vec_add1 (sw_if_indices, p[0]);
+    }
+  else /* default, HTTP_BUILTIN_METHOD_GET */
+    {
+      pool_foreach (hi, im->hw_interfaces)
+       {
+         vec_add1 (sw_if_indices, hi->sw_if_index);
+       }
+    }
+
+  s = format (s, "{%sinterface_stats%s: [\n", q, q);
+
+  for (i = 0; i < vec_len (sw_if_indices); i++)
+    {
+      si = vnet_get_sw_interface (vnm, sw_if_indices[i]);
+      if (need_comma)
+       s = format (s, ",\n");
+
+      need_comma = 1;
+
+      s = format (s, "{%sname%s: %s%U%s, ", q, q, q,
+                 format_vnet_sw_if_index_name, vnm, sw_if_indices[i], q);
+
+      stats = format_vnet_sw_interface_cntrs (stats, &vnm->interface_main, si,
+                                             1 /* want json */);
+      if (vec_len (stats))
+       s = format (s, "%v}", stats);
+      else
+       s = format (s, "%snone%s: %strue%s}", q, q, q, q);
+      vec_reset_length (stats);
+    }
+
+  s = format (s, "]}\n");
+
+out:
+  hs->data = s;
+  hs->data_offset = 0;
+  hs->cache_pool_index = ~0;
+  hs->free_data = 1;
+  vec_free (sw_if_indices);
+  vec_free (stats);
+  return 0;
+}
+
+int
+handle_get_interface_list (http_req_method_t reqtype, u8 *request,
+                          hss_session_t *hs)
+{
+  u8 *s = 0;
+  int i;
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_interface_main_t *im = &vnm->interface_main;
+  vnet_hw_interface_t *hi;
+  u32 *hw_if_indices = 0;
+  int need_comma = 0;
+
+  /* Construct vector of active hw_if_indexes ... */
+  pool_foreach (hi, im->hw_interfaces)
+    {
+      /* No point in mentioning "local0"... */
+      if (hi - im->hw_interfaces)
+       vec_add1 (hw_if_indices, hi - im->hw_interfaces);
+    }
+
+  /* Build answer */
+  s = format (s, "{\"interface_list\": [\n");
+  for (i = 0; i < vec_len (hw_if_indices); i++)
+    {
+      if (need_comma)
+       s = format (s, ",\n");
+      hi = pool_elt_at_index (im->hw_interfaces, hw_if_indices[i]);
+      s = format (s, "\"%v\"", hi->name);
+      need_comma = 1;
+    }
+  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;
+}
+
+void
+hss_builtinurl_json_handlers_init (void)
+{
+  hss_register_url_handler (handle_get_version, "version.json", HTTP_REQ_GET);
+  hss_register_url_handler (handle_get_interface_list, "interface_list.json",
+                           HTTP_REQ_GET);
+  hss_register_url_handler (handle_get_interface_stats, "interface_stats.json",
+                           HTTP_REQ_GET);
+  hss_register_url_handler (handle_get_interface_stats, "interface_stats.json",
+                           HTTP_REQ_POST);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 077371c..b8d6931 100644 (file)
 #define REPLY_MSG_ID_BASE hsm->msg_id_base
 #include <vlibapi/api_helper_macros.h>
 
-/** \brief Register a builtin GET or POST handler
- */
 __clib_export void
-http_static_server_register_builtin_handler (void *fp, char *url,
-                                            http_req_method_t request_type)
+hss_register_url_handler (hss_url_handler_t fp, const char *url,
+                         http_req_method_t request_type)
 {
   hss_main_t *hsm = &hss_main;
-  uword *p, *builtin_table;
+  uword *p, *url_table;
 
-  builtin_table = (request_type == HTTP_REQ_GET) ? hsm->get_url_handlers :
-                                                  hsm->post_url_handlers;
+  url_table = (request_type == HTTP_REQ_GET) ? hsm->get_url_handlers :
+                                              hsm->post_url_handlers;
 
-  p = hash_get_mem (builtin_table, url);
+  p = hash_get_mem (url_table, url);
 
   if (p)
     {
@@ -53,16 +51,16 @@ http_static_server_register_builtin_handler (void *fp, char *url,
       return;
     }
 
-  hash_set_mem (builtin_table, url, (uword) fp);
+  hash_set_mem (url_table, url, (uword) fp);
 
   /*
    * Need to update the hash table pointer in http_static_server_main
    * in case we just expanded it...
    */
   if (request_type == HTTP_REQ_GET)
-    hsm->get_url_handlers = builtin_table;
+    hsm->get_url_handlers = url_table;
   else
-    hsm->post_url_handlers = builtin_table;
+    hsm->post_url_handlers = url_table;
 }
 
 /** \brief API helper function for vl_api_http_static_enable_t messages
index a1eaa6e..05d6ee0 100644 (file)
@@ -67,9 +67,10 @@ typedef struct
   int inuse;
 } hss_cache_entry_t;
 
+typedef int (*hss_url_handler_t) (http_req_method_t, u8 *, hss_session_t *);
+
 /** \brief Main data structure
  */
-
 typedef struct
 {
   /** Per thread vector of session pools */
@@ -127,14 +128,20 @@ typedef struct
   u8 *uri;
   /** Threshold for switching to ptr data in http msgs */
   u32 use_ptr_thresh;
+  /** Enable the use of builtinurls */
+  u8 enable_url_handlers;
 } hss_main_t;
 
 extern hss_main_t hss_main;
 
 int hss_create (vlib_main_t *vm);
 
-void http_static_server_register_builtin_handler (void *fp, char *url,
-                                                 http_req_method_t type);
+/**
+ * Register a GET or POST URL handler
+ */
+void hss_register_url_handler (hss_url_handler_t fp, const char *url,
+                              http_req_method_t type);
+void hss_builtinurl_json_handlers_init (void);
 
 #endif /* __included_http_static_h__ */
 
index 9412449..a78b5fe 100644 (file)
@@ -294,15 +294,52 @@ done:
     session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX);
 }
 
+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)
+{
+  uword *p, *url_table;
+  hss_url_handler_t fp;
+  int rv;
+
+  if (!hsm->enable_url_handlers)
+    return -1;
+
+  /* Look for built-in GET / POST handlers */
+  url_table =
+    (rt == HTTP_REQ_GET) ? hsm->get_url_handlers : hsm->post_url_handlers;
+
+  p = hash_get_mem (url_table, request);
+  if (!p)
+    return -1;
+
+  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)
+    {
+      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;
+    }
+
+  return 0;
+}
+
 static int
 find_data (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;
-  u8 *path;
   struct stat _sb, *sb = &_sb;
   clib_error_t *error;
-  uword *p, *builtin_table;
-  http_status_code_t sc = HTTP_STATUS_OK;
+  u8 *path;
+
+  if (!try_url_handler (hsm, hs, rt, request, &sc))
+    goto done;
 
   /*
    * Construct the file to open
@@ -316,29 +353,6 @@ find_data (hss_session_t *hs, http_req_method_t rt, u8 *request)
   if (hsm->debug_level > 0)
     clib_warning ("%s '%s'", (rt == HTTP_REQ_GET) ? "GET" : "POST", path);
 
-  /* Look for built-in GET / POST handlers */
-  builtin_table =
-    (rt == HTTP_REQ_GET) ? hsm->get_url_handlers : hsm->post_url_handlers;
-
-  p = hash_get_mem (builtin_table, request);
-
-  if (p)
-    {
-      int rv;
-      int (*fp) (http_req_method_t, u8 *, hss_session_t *);
-      fp = (void *) p[0];
-      hs->path = path;
-      rv = (*fp) (rt, request, hs);
-      if (rv)
-       {
-         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;
-       }
-      goto done;
-    }
-
   /* Try to find the file. 2x special cases to find index.html */
   if (stat ((char *) path, sb) < 0     /* cant even stat the file */
       || sb->st_size < 20      /* file too small */
@@ -788,6 +802,18 @@ hss_listen (void)
   return rv;
 }
 
+static void
+hss_url_handlers_init (hss_main_t *hsm)
+{
+  if (!hsm->get_url_handlers)
+    {
+      hsm->get_url_handlers = hash_create_string (0, sizeof (uword));
+      hsm->post_url_handlers = hash_create_string (0, sizeof (uword));
+    }
+
+  hss_builtinurl_json_handlers_init ();
+}
+
 int
 hss_create (vlib_main_t *vm)
 {
@@ -814,8 +840,8 @@ hss_create (vlib_main_t *vm)
   /* Init path-to-cache hash table */
   BV (clib_bihash_init) (&hsm->name_to_data, "http cache", 128, 32 << 20);
 
-  hsm->get_url_handlers = hash_create_string (0, sizeof (uword));
-  hsm->post_url_handlers = hash_create_string (0, sizeof (uword));
+  if (hsm->enable_url_handlers)
+    hss_url_handlers_init (hsm);
 
   return 0;
 }
@@ -867,6 +893,8 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input,
       else if (unformat (line_input, "ptr-thresh %U", unformat_memory_size,
                         &hsm->use_ptr_thresh))
        ;
+      else if (unformat (line_input, "url-handlers"))
+       hsm->enable_url_handlers = 1;
       else
        {
          error = clib_error_return (0, "unknown input `%U'",
@@ -881,9 +909,9 @@ no_input:
   if (error)
     goto done;
 
-  if (hsm->www_root == 0)
+  if (hsm->www_root == 0 && !hsm->enable_url_handlers)
     {
-      error = clib_error_return (0, "Must specify www-root <path>");
+      error = clib_error_return (0, "Must set www-root or url-handlers");
       goto done;
     }
 
@@ -924,7 +952,7 @@ VLIB_CLI_COMMAND (hss_create_command, static) = {
   .short_help =
     "http static server www-root <path> [prealloc-fifos <nn>]\n"
     "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n"
-    "[ptr-thresh <nn>][debug [nn]]\n",
+    "[ptr-thresh <nn>] [url-handlers] [debug [nn]]\n",
   .function = hss_create_command_fn,
 };
 
index 35a254f..d039f7b 100644 (file)
@@ -1,5 +1,4 @@
 #include <vnet/vnet.h>
-#include <builtinurl/builtinurl.h>
 #include <http_static/http_static.h>
 #include <mactime/mactime.h>
 #include <vlib/unix/plugin.h>
@@ -160,7 +159,7 @@ mactime_url_init (vlib_main_t * vm)
 
   /* Look up the builtin URL registration handler */
   fp = vlib_get_plugin_symbol ("http_static_plugin.so",
-                              "http_static_server_register_builtin_handler");
+                              "hss_register_url_handler");
 
   if (fp == 0)
     {