summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/http_static/CMakeLists.txt1
-rw-r--r--src/plugins/http_static/FEATURE.yaml20
-rw-r--r--src/plugins/http_static/builtinurl/json_urls.c197
-rw-r--r--src/plugins/http_static/http_static.c20
-rw-r--r--src/plugins/http_static/http_static.h13
-rw-r--r--src/plugins/http_static/static_server.c90
-rw-r--r--src/plugins/mactime/builtins.c3
7 files changed, 291 insertions, 53 deletions
diff --git a/src/plugins/http_static/CMakeLists.txt b/src/plugins/http_static/CMakeLists.txt
index f9ccb15beae..cf9e41e30e5 100644
--- a/src/plugins/http_static/CMakeLists.txt
+++ b/src/plugins/http_static/CMakeLists.txt
@@ -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
diff --git a/src/plugins/http_static/FEATURE.yaml b/src/plugins/http_static/FEATURE.yaml
index d40855f2de2..ff4e147c495 100644
--- a/src/plugins/http_static/FEATURE.yaml
+++ b/src/plugins/http_static/FEATURE.yaml
@@ -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
index 00000000000..ccd70fb1799
--- /dev/null
+++ b/src/plugins/http_static/builtinurl/json_urls.c
@@ -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:
+ */
diff --git a/src/plugins/http_static/http_static.c b/src/plugins/http_static/http_static.c
index 077371cac52..b8d6931b4c6 100644
--- a/src/plugins/http_static/http_static.c
+++ b/src/plugins/http_static/http_static.c
@@ -32,19 +32,17 @@
#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
diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h
index a1eaa6e1144..05d6ee05a4c 100644
--- a/src/plugins/http_static/http_static.h
+++ b/src/plugins/http_static/http_static.h
@@ -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__ */
diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c
index 94124495bd8..a78b5fe4f2b 100644
--- a/src/plugins/http_static/static_server.c
+++ b/src/plugins/http_static/static_server.c
@@ -295,14 +295,51 @@ done:
}
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,
};
diff --git a/src/plugins/mactime/builtins.c b/src/plugins/mactime/builtins.c
index 35a254f1a25..d039f7bff7f 100644
--- a/src/plugins/mactime/builtins.c
+++ b/src/plugins/mactime/builtins.c
@@ -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)
{