*/
#include <http_static/http_static.h>
+#include <vnet/session/application.h>
#include <sys/types.h>
#include <sys/stat.h>
msg.data.headers_len = hs->resp_headers.tail_offset;
msg.data.len = msg.data.body_len + msg.data.headers_len;
- if (msg.data.len > hss_main.use_ptr_thresh)
+ if (msg.data.len > hs->use_ptr_thresh)
{
msg.data.type = HTTP_MSG_DATA_PTR;
rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
target_path = hs->target_path;
- if (!hsm->enable_url_handlers || !target_path)
+ if (!target_path)
return -1;
/* zero-length? try "index.html" */
}
static u32
-try_index_file (hss_main_t *hsm, hss_session_t *hs, u8 *path)
+try_index_file (hss_listener_t *l, hss_session_t *hs, u8 *path)
{
+ hss_main_t *hsm = &hss_main;
u8 *port_str = 0, *redirect;
transport_endpoint_t endpt;
transport_proto_t proto;
/*
* We found an index.html file, build a redirect
*/
- vec_delete (path, vec_len (hsm->www_root) - 1, 0);
+ vec_delete (path, vec_len (l->www_root) - 1, 0);
ts = session_get (hs->vpp_session_index, hs->thread_index);
session_get_endpoint (ts, &endpt, 1 /* is_local */);
u32 ce_index, max_dequeue;
http_content_type_t type;
u8 *last_modified;
+ hss_listener_t *l;
session_t *ts;
+ l = hss_listener_get (hs->listener_index);
+
/* Feature not enabled */
- if (!hsm->www_root)
+ if (!l->www_root)
return -1;
/* Discard request body */
* Construct the file to open
*/
if (!sanitized_path)
- path = format (0, "%s%c", hsm->www_root, 0);
+ path = format (0, "%s%c", l->www_root, 0);
else
- path = format (0, "%s/%s%c", hsm->www_root, sanitized_path, 0);
+ path = format (0, "%s/%s%c", l->www_root, sanitized_path, 0);
if (hsm->debug_level > 0)
clib_warning ("%s '%s'", (hs->rt == HTTP_REQ_GET) ? "GET" : "POST", path);
hs->data_offset = 0;
- ce_index = hss_cache_lookup_and_attach (&hsm->cache, path, &hs->data,
+ ce_index = hss_cache_lookup_and_attach (&l->cache, path, &hs->data,
&hs->data_len, &last_modified);
if (ce_index == ~0)
{
sc = HTTP_STATUS_NOT_FOUND;
goto done;
}
- sc = try_index_file (hsm, hs, path);
+ sc = try_index_file (l, hs, path);
goto done;
}
- ce_index = hss_cache_add_and_attach (&hsm->cache, path, &hs->data,
+ ce_index = hss_cache_add_and_attach (&l->cache, path, &hs->data,
&hs->data_len, &last_modified);
if (ce_index == ~0)
{
if (hss_add_header (hs, HTTP_HEADER_CONTENT_TYPE,
http_content_type_token (type)) ||
hss_add_header (hs, HTTP_HEADER_CACHE_CONTROL,
- (const char *) hsm->max_age_formatted,
- vec_len (hsm->max_age_formatted)) ||
+ (const char *) l->max_age_formatted,
+ vec_len (l->max_age_formatted)) ||
hss_add_header (hs, HTTP_HEADER_LAST_MODIFIED,
(const char *) last_modified, vec_len (last_modified)))
{
static void
handle_request (hss_session_t *hs)
{
- if (!try_url_handler (hs))
+ hss_listener_t *l;
+
+ l = hss_listener_get (hs->listener_index);
+
+ if (hs->left_recv > l->max_body_size)
+ {
+ start_send_data (hs, HTTP_STATUS_CONTENT_TOO_LARGE);
+ hss_session_disconnect_transport (hs);
+ return;
+ }
+
+ if (l->enable_url_handlers && !try_url_handler (hs))
return;
if (!try_file_handler (hs))
static int
hss_ts_rx_callback (session_t *ts)
{
- hss_main_t *hsm = &hss_main;
hss_session_t *hs;
http_msg_t msg;
int rv;
if (msg.data.body_len && msg.method_type == HTTP_REQ_POST)
{
- if (msg.data.body_len > hsm->max_body_size)
- {
- start_send_data (hs, HTTP_STATUS_CONTENT_TOO_LARGE);
- goto err_done;
- }
-
hs->left_recv = msg.data.body_len;
/* drop everything up to body */
svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset);
hss_ts_accept_callback (session_t *ts)
{
hss_session_t *hs;
+ session_t *ls;
u32 thresh;
hs = hss_session_alloc (ts->thread_index);
hs->vpp_session_index = ts->session_index;
hs->vpp_session_handle = session_handle (ts);
+ /* Link to listener context */
+ ls = listen_session_get_from_handle (ts->listener_handle);
+ hs->listener_index = ls->opaque;
+ hs->use_ptr_thresh = hss_listener_get (hs->listener_index)->use_ptr_thresh;
+
/* The application sets a threshold for it's fifo to get notified when
* additional data can be enqueued. We want to keep the TX fifo reasonably
* full, however avoid entering a state where the
static void
hss_ts_cleanup (session_t *s, session_cleanup_ntf_t ntf)
{
- hss_main_t *hsm = &hss_main;
hss_session_t *hs;
if (ntf == SESSION_CLEANUP_TRANSPORT)
if (hs->cache_pool_index != ~0)
{
- hss_cache_detach_entry (&hsm->cache, hs->cache_pool_index);
+ hss_listener_t *l = hss_listener_get (hs->listener_index);
+ if (l)
+ hss_cache_detach_entry (&l->cache, hs->cache_pool_index);
hs->cache_pool_index = ~0;
}
}
static int
-hss_listen (void)
+hss_listen (hss_listener_t *l, session_handle_t *lh)
{
hss_main_t *hsm = &hss_main;
- session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
vnet_listen_args_t _a, *a = &_a;
- char *uri = "tcp://0.0.0.0/80";
u8 need_crypto;
transport_endpt_ext_cfg_t *ext_cfg;
int rv;
- transport_endpt_cfg_http_t http_cfg = { hsm->keepalive_timeout, 0 };
+ transport_endpt_cfg_http_t http_cfg = { l->keepalive_timeout, 0 };
clib_memset (a, 0, sizeof (*a));
a->app_index = hsm->app_index;
- if (hsm->uri)
- uri = (char *) hsm->uri;
-
- if (parse_uri (uri, &sep))
- return -1;
-
- need_crypto = hss_transport_needs_crypto (sep.transport_proto);
+ need_crypto = hss_transport_needs_crypto (l->sep.transport_proto);
- sep.transport_proto = TRANSPORT_PROTO_HTTP;
- clib_memcpy (&a->sep_ext, &sep, sizeof (sep));
+ l->sep.transport_proto = TRANSPORT_PROTO_HTTP;
+ clib_memcpy (&a->sep_ext, &l->sep, sizeof (l->sep));
ext_cfg = session_endpoint_add_ext_cfg (
&a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
ext_cfg->crypto.ckpair_index = hsm->ckpair_index;
}
- rv = vnet_listen (a);
+ if (!(rv = vnet_listen (a)))
+ *lh = a->handle;
session_endpoint_free_ext_cfgs (&a->sep_ext);
static void
hss_url_handlers_init (hss_main_t *hsm)
{
- if (!hsm->get_url_handlers)
+ if (hsm->get_url_handlers)
+ return;
+
+ 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_listener_add (hss_listener_t *l_cfg)
+{
+ hss_main_t *hsm = &hss_main;
+ session_handle_t lh;
+ app_listener_t *al;
+ hss_listener_t *l;
+ session_t *ls;
+
+ if (hss_listen (l_cfg, &lh))
{
- hsm->get_url_handlers = hash_create_string (0, sizeof (uword));
- hsm->post_url_handlers = hash_create_string (0, sizeof (uword));
+ clib_warning ("failed to start listening");
+ return -1;
}
- hss_builtinurl_json_handlers_init ();
+ pool_get (hsm->listeners, l);
+ *l = *l_cfg;
+ l->l_index = l - hsm->listeners;
+ l->session_handle = lh;
+
+ al = app_listener_get_w_handle (lh);
+ ls = app_listener_get_session (al);
+ ls->opaque = l->l_index;
+
+ if (l->www_root)
+ hss_cache_init (&l->cache, l->cache_size, hsm->debug_level);
+ if (l->enable_url_handlers)
+ hss_url_handlers_init (hsm);
+
+ l->max_age_formatted = format (0, "max-age=%d", l->max_age);
+
+ return 0;
+}
+
+int
+hss_listener_del (hss_listener_t *l_cfg)
+{
+ hss_main_t *hsm = &hss_main;
+ hss_listener_t *l;
+ u8 found = 0;
+
+ pool_foreach (l, hsm->listeners)
+ {
+ if (clib_memcmp (&l_cfg->sep, &l->sep, sizeof (l_cfg->sep)) == 0)
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+
+ vnet_unlisten_args_t args = { .handle = l->session_handle, hsm->app_index };
+
+ vec_free (l->www_root);
+ vec_free (l->max_age_formatted);
+ hss_cache_free (&l->cache);
+ pool_put (hsm->listeners, l);
+
+ return vnet_unlisten (&args);
}
int
num_threads = 1 /* main thread */ + vtm->n_threads;
vec_validate (hsm->sessions, num_threads - 1);
+ /* Make sure session layer is enabled */
+ session_enable_disable_args_t args = { .is_en = 1,
+ .rt_engine_type =
+ RT_BACKEND_ENGINE_RULE_TABLE };
+ vnet_session_enable_disable (vm, &args);
+
if (hss_attach ())
{
clib_warning ("failed to attach server");
return -1;
}
- if (hss_listen ())
+
+ if (hsm->have_default_listener && hss_listener_add (&hsm->default_listener))
{
clib_warning ("failed to start listening");
return -1;
}
- if (hsm->www_root)
- hss_cache_init (&hsm->cache, hsm->cache_size, hsm->debug_level);
-
- if (hsm->enable_url_handlers)
- hss_url_handlers_init (hsm);
-
- hsm->max_age_formatted = format (0, "max-age=%d", hsm->max_age);
+ hsm->is_init = 1;
return 0;
}
{
unformat_input_t _line_input, *line_input = &_line_input;
hss_main_t *hsm = &hss_main;
+ hss_listener_t *l = &hsm->default_listener;
clib_error_t *error = 0;
+ char *uri = 0;
u64 seg_size;
int rv;
if (hsm->app_index != (u32) ~0)
- return clib_error_return (0, "http server already running...");
+ return clib_error_return (0, "http static server already initialized...");
hsm->prealloc_fifos = 0;
hsm->private_segment_size = 0;
hsm->fifo_size = 0;
- hsm->cache_size = 10 << 20;
- hsm->max_age = HSS_DEFAULT_MAX_AGE;
- hsm->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE;
- hsm->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT;
+
+ l->cache_size = 10 << 20;
+ l->max_age = HSS_DEFAULT_MAX_AGE;
+ l->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE;
+ l->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
- if (unformat (line_input, "www-root %s", &hsm->www_root))
- ;
- else
- if (unformat (line_input, "prealloc-fifos %d", &hsm->prealloc_fifos))
- ;
- else if (unformat (line_input, "private-segment-size %U",
- unformat_memory_size, &seg_size))
+ /* Server config */
+ if (unformat (line_input, "private-segment-size %U",
+ unformat_memory_size, &seg_size))
hsm->private_segment_size = seg_size;
else if (unformat (line_input, "fifo-size %U", unformat_memory_size,
&hsm->fifo_size))
;
- else if (unformat (line_input, "cache-size %U", unformat_memory_size,
- &hsm->cache_size))
- ;
- else if (unformat (line_input, "uri %s", &hsm->uri))
+ else if (unformat (line_input, "prealloc-fifos %d",
+ &hsm->prealloc_fifos))
;
else if (unformat (line_input, "debug %d", &hsm->debug_level))
;
- else if (unformat (line_input, "keepalive-timeout %d",
- &hsm->keepalive_timeout))
- ;
else if (unformat (line_input, "debug"))
hsm->debug_level = 1;
- else if (unformat (line_input, "ptr-thresh %U", unformat_memory_size,
- &hsm->use_ptr_thresh))
+ /* Default listener parameters */
+ else if (unformat (line_input, "uri %s", &uri))
+ ;
+ else if (unformat (line_input, "www-root %s", &l->www_root))
;
else if (unformat (line_input, "url-handlers"))
- hsm->enable_url_handlers = 1;
- else if (unformat (line_input, "max-age %d", &hsm->max_age))
+ l->enable_url_handlers = 1;
+ else if (unformat (line_input, "cache-size %U", unformat_memory_size,
+ &l->cache_size))
+ ;
+ else if (unformat (line_input, "max-age %d", &l->max_age))
;
else if (unformat (line_input, "max-body-size %U", unformat_memory_size,
- &hsm->max_body_size))
+ &l->max_body_size))
+ ;
+ else if (unformat (line_input, "keepalive-timeout %d",
+ &l->keepalive_timeout))
+ ;
+ else if (unformat (line_input, "ptr-thresh %U", unformat_memory_size,
+ &l->use_ptr_thresh))
;
else
{
if (error)
goto done;
- if (hsm->www_root == 0 && !hsm->enable_url_handlers)
+ if (l->www_root)
{
- error = clib_error_return (0, "Must set www-root or url-handlers");
- goto done;
+ /* Maintain legacy default uri behavior */
+ if (!uri)
+ uri = "tcp://0.0.0.0:80";
+ if (l->cache_size < (128 << 10))
+ {
+ error = clib_error_return (0, "cache-size must be at least 128kb");
+ vec_free (l->www_root);
+ goto done;
+ }
}
- if (hsm->cache_size < (128 << 10))
+ if (uri)
{
- error = clib_error_return (0, "cache-size must be at least 128kb");
- vec_free (hsm->www_root);
- goto done;
+ if (parse_uri (uri, &l->sep))
+ {
+ error = clib_error_return (0, "failed to parse uri %s", uri);
+ goto done;
+ }
+ hsm->have_default_listener = 1;
}
- session_enable_disable_args_t args = { .is_en = 1,
- .rt_engine_type =
- RT_BACKEND_ENGINE_RULE_TABLE };
- vnet_session_enable_disable (vm, &args);
-
if ((rv = hss_create (vm)))
{
error = clib_error_return (0, "server_create returned %d", rv);
- vec_free (hsm->www_root);
+ vec_free (l->www_root);
}
done:
VLIB_CLI_COMMAND (hss_create_command, static) = {
.path = "http static server",
.short_help =
- "http static server www-root <path> [prealloc-fifos <nn>]\n"
+ "http static server [www-root <path>] [url-handlers]\n"
"[private-segment-size <nnMG>] [fifo-size <nbytes>] [max-age <nseconds>]\n"
- "[uri <uri>] [ptr-thresh <nn>] [url-handlers] [debug [nn]]\n"
+ "[uri <uri>] [ptr-thresh <nn>] [prealloc-fifos <nn>] [debug [nn]]\n"
"[keepalive-timeout <nn>] [max-body-size <nn>]\n",
.function = hss_create_command_fn,
};
+static clib_error_t *
+hss_add_del_listener_command_fn (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ hss_main_t *hsm = &hss_main;
+ clib_error_t *error = 0;
+ hss_listener_t _l = {}, *l = &_l;
+ u8 is_add = 1;
+ char *uri = 0;
+
+ if (!hsm->is_init)
+ return clib_error_return (0, "Static server not initialized");
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "No input provided");
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "add"))
+ is_add = 1;
+ else if (unformat (line_input, "del"))
+ is_add = 0;
+ else if (unformat (line_input, "uri %s", &uri))
+ ;
+ else if (unformat (line_input, "www-root %s", &l->www_root))
+ ;
+ else if (unformat (line_input, "url-handlers"))
+ l->enable_url_handlers = 1;
+ else if (unformat (line_input, "cache-size %U", unformat_memory_size,
+ &l->cache_size))
+ ;
+ else if (unformat (line_input, "keepalive-timeout %d",
+ &l->keepalive_timeout))
+ ;
+ else if (unformat (line_input, "ptr-thresh %U", unformat_memory_size,
+ &l->use_ptr_thresh))
+ ;
+ else if (unformat (line_input, "max-age %d", &l->max_age))
+ ;
+ else if (unformat (line_input, "max-body-size %U", unformat_memory_size,
+ &l->max_body_size))
+ ;
+ else
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ break;
+ }
+ }
+ unformat_free (line_input);
+
+ if (!uri)
+ {
+ error = clib_error_return (0, "Must set uri");
+ goto done;
+ }
+
+ if (parse_uri (uri, &l->sep))
+ {
+ error = clib_error_return (0, "failed to parse uri %s", uri);
+ goto done;
+ }
+
+ if (!is_add)
+ {
+ hss_listener_del (l);
+ goto done;
+ }
+
+ if (l->www_root == 0 && !l->enable_url_handlers)
+ {
+ error = clib_error_return (0, "Must set www-root or url-handlers");
+ goto done;
+ }
+
+ if (l->cache_size < (128 << 10))
+ {
+ error = clib_error_return (0, "cache-size must be at least 128kb");
+ goto done;
+ }
+
+ if (hss_listener_add (l))
+ {
+ error = clib_error_return (0, "failed to create listener");
+ goto done;
+ }
+
+done:
+
+ vec_free (uri);
+ return error;
+}
+
+VLIB_CLI_COMMAND (hss_add_del_listener_command, static) = {
+ .path = "http static listener",
+ .short_help = "http static listener [add|del] uri <uri>\n"
+ "[www-root <path>] [url-handlers] \n",
+ .function = hss_add_del_listener_command_fn,
+};
+
static u8 *
format_hss_session (u8 *s, va_list *args)
{
return s;
}
+static u8 *
+format_hss_listener (u8 *s, va_list *args)
+{
+ hss_listener_t *l = va_arg (*args, hss_listener_t *);
+ int __clib_unused verbose = va_arg (*args, int);
+
+ s = format (
+ s, "listener %d, uri %U:%u, www-root %s, cache-size %U url-handlers %d",
+ l->l_index, format_ip46_address, &l->sep.ip, l->sep.is_ip4,
+ clib_net_to_host_u16 (l->sep.port), l->www_root, format_memory_size,
+ l->cache_size, l->enable_url_handlers);
+ return s;
+}
+
static clib_error_t *
hss_show_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
- int verbose = 0, show_cache = 0, show_sessions = 0;
+ int verbose = 0, show_cache = 0, show_sessions = 0, show_listeners = 0;
+ u32 l_index = 0;
hss_main_t *hsm = &hss_main;
- if (hsm->www_root == 0)
+ if (!hsm->is_init)
return clib_error_return (0, "Static server disabled");
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
verbose = 1;
else if (unformat (input, "cache"))
show_cache = 1;
+ else if (unformat (input, "cache %u", &l_index))
+ show_cache = 1;
else if (unformat (input, "sessions"))
show_sessions = 1;
+ else if (unformat (input, "listeners"))
+ show_listeners = 1;
else
break;
}
- if ((show_cache + show_sessions) == 0)
+ if ((show_cache + show_sessions + show_listeners) == 0)
return clib_error_return (0, "specify one or more of cache, sessions");
if (show_cache)
- vlib_cli_output (vm, "%U", format_hss_cache, &hsm->cache, verbose);
+ {
+ hss_listener_t *l = hss_listener_get (l_index);
+ if (l == 0)
+ return clib_error_return (0, "listener %d not found", l_index);
+ vlib_cli_output (vm, "%U", format_hss_cache, &l->cache, verbose);
+ }
if (show_sessions)
{
}
vec_free (session_indices);
}
+
+ if (show_listeners)
+ {
+ hss_listener_t *l;
+ pool_foreach (l, hsm->listeners)
+ {
+ vlib_cli_output (vm, "%U", format_hss_listener, l, verbose);
+ }
+ }
return 0;
}
?*/
VLIB_CLI_COMMAND (hss_show_command, static) = {
.path = "show http static server",
- .short_help = "show http static server sessions cache [verbose [<nn>]]",
+ .short_help = "show http static server [sessions] [cache] [listeners] "
+ "[verbose [<nn>]]",
.function = hss_show_command_fn,
};
vlib_cli_command_t *cmd)
{
hss_main_t *hsm = &hss_main;
- u32 busy_items = 0;
+ u32 busy_items = 0, l_index = 0;
+ hss_listener_t *l;
- if (hsm->www_root == 0)
+ if (!hsm->is_init)
return clib_error_return (0, "Static server disabled");
- busy_items = hss_cache_clear (&hsm->cache);
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "index %u", &l_index))
+ ;
+ else
+ {
+ return clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, input);
+ }
+ }
+
+ l = hss_listener_get (l_index);
+ if (l == 0)
+ return clib_error_return (0, "listener %d not found", l_index);
+
+ busy_items = hss_cache_clear (&l->cache);
if (busy_items > 0)
vlib_cli_output (vm, "Note: %d busy items still in cache...", busy_items);
?*/
VLIB_CLI_COMMAND (clear_hss_cache_command, static) = {
.path = "clear http static cache",
- .short_help = "clear http static cache",
+ .short_help = "clear http static cache [index <index>]",
.function = hss_clear_cache_command_fn,
};