#include <vnet/session/application.h>
#include <vnet/session/application_interface.h>
#include <vnet/session/session.h>
-#include <vppinfra/tw_timer_2t_1w_2048sl.h>
#include <vppinfra/unix.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <http_static/http_static.h>
-#include <vppinfra/bihash_vec8_8.h>
#include <vppinfra/bihash_template.c>
-/** @file
- Simple Static http server, sufficient to
+/** @file Static http server, sufficient to
serve .html / .css / .js content.
*/
/*? %%clicmd:group_label Static HTTP Server %% ?*/
-/** \brief Session States
- */
-
-typedef enum
-{
- /** Session is closed */
- HTTP_STATE_CLOSED,
- /** Session is established */
- HTTP_STATE_ESTABLISHED,
- /** Session has sent an OK response */
- HTTP_STATE_OK_SENT,
- /** Session has sent an HTML response */
- HTTP_STATE_SEND_MORE_DATA,
- /** Number of states */
- HTTP_STATE_N_STATES,
-} http_session_state_t;
-
-typedef enum
-{
- CALLED_FROM_RX,
- CALLED_FROM_TX,
- CALLED_FROM_TIMER,
-} state_machine_called_from_t;
-
-
-/** \brief Application session
- */
-typedef struct
-{
- CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
- /** Base class instance variables */
-#define _(type, name) type name;
- foreach_app_session_field
-#undef _
- /** rx thread index */
- u32 thread_index;
- /** rx buffer */
- u8 *rx_buf;
- /** vpp session index, handle */
- u32 vpp_session_index;
- u64 vpp_session_handle;
- /** Timeout timer handle */
- u32 timer_handle;
- /** Fully-resolved file path */
- u8 *path;
- /** File data, a vector */
- u8 *data;
- /** Current data send offset */
- u32 data_offset;
- /** File cache pool index */
- u32 cache_pool_index;
- /** state machine called from... */
- state_machine_called_from_t called_from;
-} http_session_t;
-
-/** \brief In-memory file data cache entry
- */
-typedef struct
-{
- /** Name of the file */
- u8 *filename;
- /** Contents of the file, as a u8 * vector */
- u8 *data;
- /** Last time the cache entry was used */
- f64 last_used;
- /** Cache LRU links */
- u32 next_index;
- u32 prev_index;
- /** Reference count, so we don't recycle while referenced */
- int inuse;
-} file_data_cache_t;
-
-/** \brief Main data structure
- */
-
-typedef struct
-{
- /** Per thread vector of session pools */
- http_session_t **sessions;
- /** Session pool reader writer lock */
- clib_rwlock_t sessions_lock;
- /** vpp session to http session index map */
- u32 **session_to_http_session;
-
- /** vpp message/event queue */
- svm_msg_q_t **vpp_queue;
-
- /** Unified file data cache pool */
- file_data_cache_t *cache_pool;
- /** Hash table which maps file name to file data */
- BVT (clib_bihash) name_to_data;
-
- /** Current cache size */
- u64 cache_size;
- /** Max cache size in bytes */
- u64 cache_limit;
- /** Number of cache evictions */
- u64 cache_evictions;
-
- /** Cache LRU listheads */
- u32 first_index;
- u32 last_index;
-
- /** root path to be served */
- u8 *www_root;
-
- /** Server's event queue */
- svm_queue_t *vl_input_queue;
-
- /** API client handle */
- u32 my_client_index;
-
- /** Application index */
- u32 app_index;
-
- /** Process node index for event scheduling */
- u32 node_index;
-
- /** Session cleanup timer wheel */
- tw_timer_wheel_2t_1w_2048sl_t tw;
- clib_spinlock_t tw_lock;
-
- /** Time base, so we can generate browser cache control http spew */
- clib_timebase_t timebase;
-
- /** Number of preallocated fifos, usually 0 */
- u32 prealloc_fifos;
- /** Private segment size, usually 0 */
- u32 private_segment_size;
- /** Size of the allocated rx, tx fifos, roughly 8K or so */
- u32 fifo_size;
- /** The bind URI, defaults to tcp://0.0.0.0/80 */
- u8 *uri;
- vlib_main_t *vlib_main;
-} http_static_server_main_t;
-
http_static_server_main_t http_static_server_main;
/** \brief Format the called-from enum
static u8 *
format_state_machine_called_from (u8 * s, va_list * args)
{
- state_machine_called_from_t cf =
- va_arg (*args, state_machine_called_from_t);
+ http_state_machine_called_from_t cf =
+ va_arg (*args, http_state_machine_called_from_t);
char *which = "bogus!";
switch (cf)
clib_rwlock_writer_unlock (&http_static_server_main.sessions_lock);
}
+/** \brief Start a session cleanup timer
+ */
+static void
+http_static_server_session_timer_start (http_session_t * hs)
+{
+ http_static_server_main_t *hsm = &http_static_server_main;
+ u32 hs_handle;
+
+ /* The session layer may fire a callback at a later date... */
+ if (!pool_is_free (hsm->sessions[hs->thread_index], hs))
+ {
+ hs_handle = hs->thread_index << 24 | hs->session_index;
+ clib_spinlock_lock (&http_static_server_main.tw_lock);
+ hs->timer_handle = tw_timer_start_2t_1w_2048sl
+ (&http_static_server_main.tw, hs_handle, 0, 60);
+ clib_spinlock_unlock (&http_static_server_main.tw_lock);
+ }
+}
+
+/** \brief stop a session cleanup timer
+ */
+static void
+http_static_server_session_timer_stop (http_session_t * hs)
+{
+ if (hs->timer_handle == ~0)
+ return;
+ clib_spinlock_lock (&http_static_server_main.tw_lock);
+ tw_timer_stop_2t_1w_2048sl (&http_static_server_main.tw, hs->timer_handle);
+ clib_spinlock_unlock (&http_static_server_main.tw_lock);
+}
+
/** \brief Allocate an http session
*/
static http_session_t *
{
http_static_server_main_t *hsm = &http_static_server_main;
http_session_t *hs;
- pool_get (hsm->sessions[thread_index], hs);
- memset (hs, 0, sizeof (*hs));
+ pool_get_aligned_zero_numa (hsm->sessions[thread_index], hs,
+ 0 /* not aligned */ ,
+ 1 /* zero */ ,
+ os_get_numa_index ());
hs->session_index = hs - hsm->sessions[thread_index];
hs->thread_index = thread_index;
hs->timer_handle = ~0;
http_static_server_session_free (http_session_t * hs)
{
http_static_server_main_t *hsm = &http_static_server_main;
+
+ /* Make sure the timer is stopped... */
+ http_static_server_session_timer_stop (hs);
pool_put (hsm->sessions[hs->thread_index], hs);
+
if (CLIB_DEBUG)
- memset (hs, 0xfa, sizeof (*hs));
+ {
+ u32 save_thread_index;
+ save_thread_index = hs->thread_index;
+ /* Poison the entry, preserve timer state and thread index */
+ memset (hs, 0xfa, sizeof (*hs));
+ hs->timer_handle = ~0;
+ hs->thread_index = save_thread_index;
+ }
}
/** \brief add a session to the vpp < -- > http session index map
return 0;
}
-/** \brief Start a session cleanup timer
- */
-
-static void
-http_static_server_session_timer_start (http_session_t * hs)
-{
- u32 hs_handle;
- hs_handle = hs->thread_index << 24 | hs->session_index;
- clib_spinlock_lock (&http_static_server_main.tw_lock);
- hs->timer_handle = tw_timer_start_2t_1w_2048sl (&http_static_server_main.tw,
- hs_handle, 0, 60);
- clib_spinlock_unlock (&http_static_server_main.tw_lock);
-}
-
-/** \brief stop a session cleanup timer
- */
-static void
-http_static_server_session_timer_stop (http_session_t * hs)
-{
- if (hs->timer_handle == ~0)
- return;
- clib_spinlock_lock (&http_static_server_main.tw_lock);
- tw_timer_stop_2t_1w_2048sl (&http_static_server_main.tw, hs->timer_handle);
- clib_spinlock_unlock (&http_static_server_main.tw_lock);
-}
-
-/** \brief Clean up an http session
+/** \brief Detach cache entry from session
*/
static void
{
ep = pool_elt_at_index (hsm->cache_pool, hs->cache_pool_index);
ep->inuse--;
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("index %d refcnt now %d", hs->cache_pool_index,
ep->inuse);
}
hs->cache_pool_index = ~0;
+ if (hs->free_data)
+ vec_free (hs->data);
hs->data = 0;
hs->data_offset = 0;
+ hs->free_data = 0;
vec_free (hs->path);
}
+/** \brief clean up a session
+ */
+
static void
http_static_server_session_cleanup (http_session_t * hs)
{
http_static_server_session_lookup_del (hs->thread_index,
hs->vpp_session_index);
vec_free (hs->rx_buf);
- http_static_server_session_timer_stop (hs);
http_static_server_session_free (hs);
}
"Date: %U GMT\r\n"
"Expires: %U GMT\r\n"
"Server: VPP Static\r\n"
- "Content-Type: text/%s\r\n"
+ "Content-Type: %s\r\n"
"Content-Length: %d\r\n\r\n";
/* *INDENT-ON* */
static_send_data (http_session_t * hs, u8 * data, u32 length, u32 offset)
{
u32 bytes_to_send;
+ http_static_server_main_t *hsm = &http_static_server_main;
bytes_to_send = length - offset;
/* Made any progress? */
if (actual_transfer <= 0)
{
- if (bytes_to_send > 0)
+ if (hsm->debug_level > 0 && bytes_to_send > 0)
clib_warning ("WARNING: still %d bytes to send", bytes_to_send);
return offset;
}
offset += actual_transfer;
bytes_to_send -= actual_transfer;
- if (bytes_to_send > 0)
+ if (hsm->debug_level && bytes_to_send > 0)
clib_warning ("WARNING: still %d bytes to send", bytes_to_send);
if (svm_fifo_set_event (hs->tx_fifo))
*/
static int
state_closed (session_t * s, http_session_t * hs,
- state_machine_called_from_t cf)
+ http_state_machine_called_from_t cf)
{
- clib_warning ("http session %d, called from %U",
+ clib_warning ("WARNING: http session %d, called from %U",
hs->session_index, format_state_machine_called_from, cf);
- return 0;
+ return -1;
}
static void
http_static_server_session_cleanup (hs);
}
+/** \brief Register a builtin GET or POST handler
+ */
+void http_static_server_register_builtin_handler
+ (void *fp, char *url, int request_type)
+{
+ http_static_server_main_t *hsm = &http_static_server_main;
+ uword *p, *builtin_table;
+
+ builtin_table = (request_type == HTTP_BUILTIN_METHOD_GET)
+ ? hsm->get_url_handlers : hsm->post_url_handlers;
+
+ p = hash_get_mem (builtin_table, url);
+
+ if (p)
+ {
+ clib_warning ("WARNING: attempt to replace handler for %s '%s' ignored",
+ (request_type == HTTP_BUILTIN_METHOD_GET) ?
+ "GET" : "POST", url);
+ return;
+ }
+
+ hash_set_mem (builtin_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_BUILTIN_METHOD_GET)
+ hsm->get_url_handlers = builtin_table;
+ else
+ hsm->post_url_handlers = builtin_table;
+}
+
+static int
+v_find_index (u8 * vec, char *str)
+{
+ int start_index;
+ u32 slen = (u32) strnlen_s_inline (str, 8);
+ u32 vlen = vec_len (vec);
+
+ ASSERT (slen > 0);
+
+ if (vlen <= slen)
+ return -1;
+
+ for (start_index = 0; start_index < (vlen - slen); start_index++)
+ {
+ if (!memcmp (vec, str, slen))
+ return start_index;
+ }
+
+ return -1;
+}
+
/** \brief established state - waiting for GET, POST, etc.
*/
static int
state_established (session_t * s, http_session_t * hs,
- state_machine_called_from_t cf)
+ http_state_machine_called_from_t cf)
{
http_static_server_main_t *hsm = &http_static_server_main;
- u32 request_len;
u8 *request = 0;
u8 *path;
int i, rv;
struct stat _sb, *sb = &_sb;
clib_error_t *error;
+ u8 request_type = HTTP_BUILTIN_METHOD_GET;
+ u8 save_byte = 0;
+ uword *p, *builtin_table;
/* Read data from the sessison layer */
rv = session_rx_request (hs);
/* Process the client request */
request = hs->rx_buf;
- request_len = vec_len (request);
- if (vec_len (request) < 7)
+ if (vec_len (request) < 8)
{
send_error (hs, "400 Bad Request");
close_session (hs);
- return 0;
+ return -1;
}
- /* We only handle GET requests at the moment */
- for (i = 0; i < request_len - 4; i++)
+ if ((i = v_find_index (request, "GET ")) >= 0)
+ goto find_end;
+ else if ((i = v_find_index (request, "POST ")) >= 0)
{
- if (request[i] == 'G' &&
- request[i + 1] == 'E' &&
- request[i + 2] == 'T' && request[i + 3] == ' ')
- goto find_end;
+ request_type = HTTP_BUILTIN_METHOD_POST;
+ goto find_end;
}
+
+ if (hsm->debug_level > 1)
+ clib_warning ("Unknown http method");
+
send_error (hs, "405 Method Not Allowed");
close_session (hs);
- return 0;
+ return -1;
find_end:
- /* Lose "GET " */
- vec_delete (request, i + 5, 0);
+ /* Lose "GET " or "POST " */
+ vec_delete (request, i + 5 + request_type, 0);
- /* Lose stuff to the right of the path */
+ /* Temporarily drop in a NULL byte for lookup purposes */
for (i = 0; i < vec_len (request); i++)
{
if (request[i] == ' ' || request[i] == '?')
{
+ save_byte = request[i];
request[i] = 0;
break;
}
else
path = format (0, "%s/%s%c", hsm->www_root, request, 0);
- if (1)
- clib_warning ("GET '%s'", path);
+ if (hsm->debug_level > 0)
+ clib_warning ("%s '%s'", (request_type) == HTTP_BUILTIN_METHOD_GET ?
+ "GET" : "POST", path);
+
+ /* Look for built-in GET / POST handlers */
+ builtin_table = (request_type == HTTP_BUILTIN_METHOD_GET) ?
+ hsm->get_url_handlers : hsm->post_url_handlers;
+
+ p = hash_get_mem (builtin_table, request);
+
+ if (save_byte != 0)
+ request[i] = save_byte;
+
+ if (p)
+ {
+ int rv;
+ int (*fp) (http_builtin_method_type_t, u8 *, http_session_t *);
+ fp = (void *) p[0];
+ hs->path = path;
+ rv = (*fp) (request_type, request, hs);
+ if (rv)
+ {
+ clib_warning ("builtin handler %llx hit on %s '%s' but failed!",
+ p[0], (request_type == HTTP_BUILTIN_METHOD_GET) ?
+ "GET" : "POST", request);
+ send_error (hs, "404 Not Found");
+ close_session (hs);
+ return -1;
+ }
+ vec_reset_length (hs->rx_buf);
+ goto send_ok;
+ }
+ vec_reset_length (hs->rx_buf);
+ /* poison request, it's not valid anymore */
+ request = 0;
+ /* The static server itself doesn't do POSTs */
+ if (request_type == HTTP_BUILTIN_METHOD_POST)
+ {
+ send_error (hs, "404 Not Found");
+ close_session (hs);
+ return -1;
+ }
/* Try to find the file. 2x special cases to find index.html */
if (stat ((char *) path, sb) < 0 /* cant even stat the file */
vec_free (path);
send_error (hs, "404 Not Found");
close_session (hs);
- return 0;
+ return -1;
}
else
{
format_ip46_address, &endpoint.ip,
endpoint.is_ip4,
print_port ? port_str : (u8 *) "", path);
- if (1)
+ if (hsm->debug_level > 0)
clib_warning ("redirect: %s", redirect);
vec_free (port_str);
vec_free (redirect);
vec_free (path);
close_session (hs);
- return 0;
+ return -1;
}
}
}
kv.key = (u64) hs->path;
if (BV (clib_bihash_search) (&hsm->name_to_data, &kv, &kv) == 0)
{
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("lookup '%s' returned %lld", kv.key, kv.value);
/* found the data.. */
lru_update (hsm, dp, vlib_time_now (hsm->vlib_main));
hs->cache_pool_index = dp - hsm->cache_pool;
dp->inuse++;
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("index %d refcnt now %d", hs->cache_pool_index,
dp->inuse);
}
else
{
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("lookup '%s' failed", kv.key, kv.value);
/* Need to recycle one (or more cache) entries? */
if (hsm->cache_size > hsm->cache_limit)
/* Which could be in use... */
if (dp->inuse)
{
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("index %d in use refcnt %d",
dp - hsm->cache_pool, dp->inuse);
{
clib_warning ("LRU delete '%s' FAILED!", dp->filename);
}
- else if (0)
+ else if (hsm->debug_level > 1)
clib_warning ("LRU delete '%s' ok", dp->filename);
lru_remove (hsm, dp);
hsm->cache_evictions++;
vec_free (dp->filename);
vec_free (dp->data);
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("pool put index %d", dp - hsm->cache_pool);
pool_put (hsm->cache_pool, dp);
if (hsm->cache_size < hsm->cache_limit)
clib_error_report (error);
vec_free (hs->path);
close_session (hs);
- return 0;
+ return -1;
}
/* Create a cache entry for it */
pool_get (hsm->cache_pool, dp);
dp->data = hs->data;
hs->cache_pool_index = dp - hsm->cache_pool;
dp->inuse++;
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("index %d refcnt now %d", hs->cache_pool_index,
dp->inuse);
lru_add (hsm, dp, vlib_time_now (hsm->vlib_main));
kv.key = (u64) vec_dup (hs->path);
kv.value = dp - hsm->cache_pool;
/* Add to the lookup table */
- if (0)
+ if (hsm->debug_level > 1)
clib_warning ("add '%s' value %lld", kv.key, kv.value);
if (BV (clib_bihash_add_del) (&hsm->name_to_data, &kv,
hs->data_offset = 0;
}
/* send 200 OK first */
+send_ok:
static_send_data (hs, (u8 *) "HTTP/1.1 200 OK\r\n", 17, 0);
hs->session_state = HTTP_STATE_OK_SENT;
return 1;
static int
state_send_more_data (session_t * s, http_session_t * hs,
- state_machine_called_from_t cf)
+ http_state_machine_called_from_t cf)
{
/* Start sending data */
static int
state_sent_ok (session_t * s, http_session_t * hs,
- state_machine_called_from_t cf)
+ http_state_machine_called_from_t cf)
{
http_static_server_main_t *hsm = &http_static_server_main;
char *suffix;
while (*suffix != '.')
suffix--;
suffix++;
- http_type = "html";
+ http_type = "text/html";
if (!clib_strcmp (suffix, "css"))
- http_type = "css";
+ http_type = "text/css";
else if (!clib_strcmp (suffix, "js"))
- http_type = "javascript";
-
+ http_type = "text/javascript";
+ else if (!clib_strcmp (suffix, "json"))
+ http_type = "application/json";
if (hs->data == 0)
{
static inline int
http_static_server_rx_tx_callback (session_t * s,
- state_machine_called_from_t cf)
+ http_state_machine_called_from_t cf)
{
http_session_t *hs;
- int (*fp) (session_t *, http_session_t *, state_machine_called_from_t);
+ int (*fp) (session_t *, http_session_t *, http_state_machine_called_from_t);
int rv;
/* Acquire a reader lock on the session table */
return 0;
}
+ /* Execute state machine for this session */
do
{
fp = state_funcs[hs->session_state];
rv = (*fp) (s, hs, cf);
+ if (rv < 0)
+ goto session_closed;
}
while (rv);
+ /* Reset the session expiration timer */
+ http_static_server_session_timer_stop (hs);
+ http_static_server_session_timer_start (hs);
+
+session_closed:
http_static_server_sessions_reader_unlock ();
return 0;
}
static int
http_static_server_session_connected_callback (u32 app_index, u32 api_context,
- session_t * s, u8 is_fail)
+ session_t * s,
+ session_error_t err)
{
clib_warning ("called...");
return -1;
hsm->fifo_size ? hsm->fifo_size : 32 << 10;
a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hsm->prealloc_fifos;
- a->options[APP_OPTIONS_TLS_ENGINE] = TLS_ENGINE_OPENSSL;
+ a->options[APP_OPTIONS_TLS_ENGINE] = CRYPTO_ENGINE_OPENSSL;
if (vnet_application_attach (a))
{
static void
http_static_server_session_cleanup_cb (void *hs_handlep)
{
+ http_static_server_main_t *hsm = &http_static_server_main;
http_session_t *hs;
uword hs_handle;
hs_handle = pointer_to_uword (hs_handlep);
hs =
http_static_server_session_get (hs_handle >> 24, hs_handle & 0x00FFFFFF);
+
+ if (hsm->debug_level > 1)
+ clib_warning ("terminate thread %d index %d hs %llx",
+ hs_handle >> 24, hs_handle & 0x00FFFFFF, hs);
if (!hs)
return;
hs->timer_handle = ~0;
/* 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));
+
/* Init timer wheel and process */
tw_timer_wheel_init_2t_1w_2048sl (&hsm->tw, http_expired_timers_dispatch,
1.0 /* timer interval */ , ~0);
else if (unformat (line_input, "uri %s", &hsm->uri))
;
+ else if (unformat (line_input, "debug %d", &hsm->debug_level))
+ ;
+ else if (unformat (line_input, "debug"))
+ hsm->debug_level = 1;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, line_input);
{
.path = "http static server",
.short_help = "http static server www-root <path> [prealloc-fifos <nn>]\n"
- "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n",
+ "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n"
+ "[debug [nn]]\n",
.function = http_static_server_create_command_fn,
};
/* *INDENT-ON* */
* @clistart
* show http static server
* @cliend
- * @cliexcmd{show http static server [verbose]}
+ * @cliexcmd{show http static server sessions cache [verbose [nn]]}
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (http_show_static_server_command, static) =
};
/* *INDENT-ON* */
+static clib_error_t *
+http_clear_static_cache_command_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ http_static_server_main_t *hsm = &http_static_server_main;
+ file_data_cache_t *dp;
+ u32 free_index;
+ u32 busy_items = 0;
+ BVT (clib_bihash_kv) kv;
+
+ if (hsm->www_root == 0)
+ return clib_error_return (0, "Static server disabled");
+
+ http_static_server_sessions_reader_lock ();
+
+ /* Walk the LRU list to find active entries */
+ free_index = hsm->last_index;
+ while (free_index != ~0)
+ {
+ dp = pool_elt_at_index (hsm->cache_pool, free_index);
+ free_index = dp->prev_index;
+ /* Which could be in use... */
+ if (dp->inuse)
+ {
+ busy_items++;
+ free_index = dp->next_index;
+ continue;
+ }
+ kv.key = (u64) (dp->filename);
+ kv.value = ~0ULL;
+ if (BV (clib_bihash_add_del) (&hsm->name_to_data, &kv,
+ 0 /* is_add */ ) < 0)
+ {
+ clib_warning ("BUG: cache clear delete '%s' FAILED!", dp->filename);
+ }
+
+ lru_remove (hsm, dp);
+ hsm->cache_size -= vec_len (dp->data);
+ hsm->cache_evictions++;
+ vec_free (dp->filename);
+ vec_free (dp->data);
+ if (hsm->debug_level > 1)
+ clib_warning ("pool put index %d", dp - hsm->cache_pool);
+ pool_put (hsm->cache_pool, dp);
+ free_index = hsm->last_index;
+ }
+ http_static_server_sessions_reader_unlock ();
+ if (busy_items > 0)
+ vlib_cli_output (vm, "Note: %d busy items still in cache...", busy_items);
+ else
+ vlib_cli_output (vm, "Cache cleared...");
+ return 0;
+}
+
+/*?
+ * Clear the static http server cache, to force the server to
+ * reload content from backing files
+ *
+ * @cliexpar
+ * This command clear the static http server cache
+ * @clistart
+ * clear http static cache
+ * @cliend
+ * @cliexcmd{clear http static cache}
+?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (clear_http_static_cache_command, static) =
+{
+ .path = "clear http static cache",
+ .short_help = "clear http static cache",
+ .function = http_clear_static_cache_command_fn,
+};
+/* *INDENT-ON* */
+
static clib_error_t *
http_static_server_main_init (vlib_main_t * vm)
{
hsm->first_index = hsm->last_index = ~0;
clib_timebase_init (&hsm->timebase, 0 /* GMT */ ,
- CLIB_TIMEBASE_DAYLIGHT_NONE);
+ CLIB_TIMEBASE_DAYLIGHT_NONE,
+ &vm->clib_time /* share the system clock */ );
return 0;
}
VLIB_INIT_FUNCTION (http_static_server_main_init);
/*
-* fd.io coding-style-patch-verification: ON
-*
-* Local Variables:
-* eval: (c-set-style "gnu")
-* End:
-*/
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */