21 #include <sys/types.h> 43 char *which =
"bogus!";
61 s =
format (s,
"%s", which);
112 (&http_static_server_main.
tw, hs_handle, 0, 60);
125 tw_timer_stop_2t_1w_2048sl (&http_static_server_main.
tw, hs->
timer_handle);
137 memset (hs, 0,
sizeof (*hs));
138 hs->session_index = hs - hsm->
sessions[thread_index];
169 u32 save_thread_index;
172 memset (hs, 0xfa,
sizeof (*hs));
271 a->app_index = http_static_server_main.
app_index;
281 "Content-Type: text/html\r\n" 282 "Connection: close\r\n" 283 "Pragma: no-cache\r\n" 284 "Content-Length: 0\r\n\r\n";
290 "Expires: %U GMT\r\n" 291 "Server: VPP Static\r\n" 292 "Content-Type: %s\r\n" 293 "Content-Length: %d\r\n\r\n";
310 bytes_to_send = length -
offset;
312 while (bytes_to_send > 0)
317 (hs->tx_fifo, bytes_to_send, data + offset);
320 if (actual_transfer <= 0)
323 clib_warning (
"WARNING: still %d bytes to send", bytes_to_send);
328 offset += actual_transfer;
329 bytes_to_send -= actual_transfer;
332 clib_warning (
"WARNING: still %d bytes to send", bytes_to_send);
366 u32 max_dequeue, cursize;
377 ASSERT (n_read == max_dequeue);
381 _vec_len (hs->
rx_buf) = cursize + n_read;
396 last_timestamp = 1e70;
397 for (i = 1, index = hsm->
first_index; index != ~0;)
404 clib_warning (
"%d[%d]: last used %.6f, last_timestamp %.6f",
412 last_timestamp = 0.0;
413 for (i = 1, index = hsm->
last_index; index != ~0;)
420 clib_warning (
"%d[%d]: last used %.6f, last_timestamp %.6f",
525 clib_warning (
"WARNING: http session %d, called from %U",
540 (
void *fp,
char *url,
int request_type)
543 uword *p, *builtin_table;
552 clib_warning (
"WARNING: attempt to replace handler for %s '%s' ignored",
554 "GET" :
"POST", url);
582 for (start_index = 0; start_index < (vlen - slen); start_index++)
584 if (!memcmp (vec, str, slen))
601 struct stat _sb, *sb = &_sb;
605 uword *p, *builtin_table;
641 vec_delete (request, i + 5 + request_type, 0);
644 for (i = 0; i <
vec_len (request); i++)
646 if (request[i] ==
' ' || request[i] ==
'?')
648 save_byte = request[
i];
658 if (request[0] ==
'/')
665 "GET" :
"POST", path);
674 request[
i] = save_byte;
682 rv = (*fp) (request_type,
request, hs);
685 clib_warning (
"builtin handler %llx hit on %s '%s' but failed!",
687 "GET" :
"POST", request);
707 if (stat ((
char *) path, sb) < 0
709 || (sb->st_mode & S_IFMT) != S_IFREG )
713 _vec_len (path) -= 1;
714 path =
format (path,
"index.html%c", 0);
715 if (stat ((
char *) path, sb) < 0
717 || (sb->st_mode & S_IFMT) != S_IFREG )
719 _vec_len (path) = save_length;
720 path =
format (path,
"/index.html%c", 0);
723 if (stat ((
char *) path, sb) < 0
725 || (sb->st_mode & S_IFMT) != S_IFREG )
750 local_port = clib_net_to_host_u16 (endpoint.port);
754 if ((proto == TRANSPORT_PROTO_TCP && local_port != 80)
755 || (proto == TRANSPORT_PROTO_TLS && local_port != 443))
758 port_str =
format (0,
":%u", (
u32) local_port);
761 redirect =
format (0,
"HTTP/1.1 301 Moved Permanently\r\n" 762 "Location: http%s://%U%s%s\r\n\r\n",
763 proto == TRANSPORT_PROTO_TLS ?
"s" :
"",
766 print_port ? port_str : (
u8 *)
"", path);
786 BVT (clib_bihash_kv) kv;
793 if (BV (clib_bihash_search) (&hsm->name_to_data, &kv, &kv) == 0)
796 clib_warning (
"lookup '%s' returned %lld", kv.key, kv.value);
818 while (free_index != ~0)
866 memset (dp, 0,
sizeof (*dp));
936 while (*suffix !=
'.')
939 http_type =
"text/html";
941 http_type =
"text/css";
943 http_type =
"text/javascript";
945 http_type =
"application/json";
960 http_response =
format (0, http_response_template,
967 if (offset !=
vec_len (http_response))
1005 clib_warning (
"No http session for thread %d session_index %d",
1014 fp = state_funcs[hs->session_state];
1015 rv = (*fp) (s, hs, cf);
1017 goto session_closed;
1136 .session_disconnect_callback =
1153 u32 segment_size = 128 << 20;
1161 a->api_client_index = ~0;
1162 a->name =
format (0,
"test_http_static_server");
1184 a_cert->app_index = a->app_index;
1190 a_key->app_index = a->app_index;
1205 a->uri =
"tcp://0.0.0.0/80";
1207 a->uri = (
char *) hsm->
uri;
1223 hs_handle >> 24, hs_handle & 0x00FFFFFF, hs);
1239 for (i = 0; i <
vec_len (expired_timers); i++)
1242 hs_handle = expired_timers[
i] & 0x7FFFFFFF;
1256 f64 now, timeout = 1.0;
1257 uword *event_data = 0;
1258 uword __clib_unused event_type;
1268 tw_timer_expire_timers_2t_1w_2048sl (&hsm->
tw, now);
1281 .name =
"static-http-server-process",
1282 .state = VLIB_NODE_STATE_DISABLED,
1323 VLIB_NODE_STATE_POLLING);
1324 n =
vlib_get_node (vm, http_static_server_process_node.index);
1335 u32 private_segment_size,
1336 u8 * www_root,
u8 * uri)
1349 return VNET_API_ERROR_INVALID_VALUE;
1352 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
1364 return VNET_API_ERROR_INIT_FAILED;
1392 if (
unformat (line_input,
"www-root %s", &www_root))
1397 else if (
unformat (line_input,
"private-segment-size %U",
1400 if (seg_size >= 0x100000000ULL)
1416 "cache-size must be at least 128kb");
1420 else if (
unformat (line_input,
"uri %s", &hsm->
uri))
1424 else if (
unformat (line_input,
"debug"))
1475 .path =
"http static server",
1476 .short_help =
"http static server www-root <path> [prealloc-fifos <nn>]\n" 1477 "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n" 1489 f64 now = va_arg (*args,
f64);
1494 s =
format (s,
"%40s%12s%20s",
"File",
"Size",
"Age");
1506 char *state_string =
"bogus!";
1511 state_string =
"closed";
1514 state_string =
"established";
1517 state_string =
"ok sent";
1520 state_string =
"send more data";
1526 return format (s,
"%s", state_string);
1533 int verbose = va_arg (*args,
int);
1535 s =
format (s,
"[%d]: state %U", hs->session_index,
1539 s =
format (s,
"\n path %s, data length %u, data_offset %u",
1555 int show_sessions = 0;
1564 if (
unformat (input,
"verbose %d", &verbose))
1566 else if (
unformat (input,
"verbose"))
1568 else if (
unformat (input,
"cache"))
1570 else if (
unformat (input,
"sessions"))
1576 if ((show_cache + show_sessions) == 0)
1584 (vm,
"www_root %s, cache size %lld bytes, limit %lld bytes, " 1610 u32 *session_indices = 0;
1621 vec_add1 (session_indices, hs - hsm->sessions[i]);
1625 for (j = 0; j <
vec_len (session_indices); j++)
1629 (hsm->
sessions[i], session_indices[j]),
1653 .path =
"show http static server",
1654 .short_help =
"show http static server sessions cache [verbose [<nn>]]",
1668 BVT (clib_bihash_kv) kv;
1677 while (free_index != ~0)
1708 vlib_cli_output (vm,
"Note: %d busy items still in cache...", busy_items);
1728 .path =
"clear http static cache",
1729 .short_help =
"clear http static cache",
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
static void clib_rwlock_reader_lock(clib_rwlock_t *p)
static int app_recv_stream_raw(svm_fifo_t *f, u8 *buf, u32 len, u8 clear_evt, u8 peek)
u8 * filename
Name of the file.
u8 * format_http_session(u8 *s, va_list *args)
static void lru_remove(http_static_server_main_t *hsm, file_data_cache_t *ep)
Remove a data cache entry from the LRU lists.
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
static http_session_t * http_static_server_session_lookup(u32 thread_index, u32 s_index)
lookup a session in the vpp < – > http session index map
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
session_type_t session_type
Type built from transport and network protocol types.
static void lru_add(http_static_server_main_t *hsm, file_data_cache_t *ep, f64 now)
Add an entry to the LRU lists, tag w/ supplied timestamp.
static f64 vlib_process_wait_for_event_or_clock(vlib_main_t *vm, f64 dt)
Suspend a cooperative multi-tasking thread Waits for an event, or for the indicated number of seconds...
static void clib_rwlock_writer_lock(clib_rwlock_t *p)
static void http_static_server_session_cleanup(http_session_t *hs)
clean up a session
static const char * http_response
u32 session_index
Index in thread pool where session was allocated.
static clib_error_t * http_clear_static_cache_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
static svm_msg_q_t * session_main_get_vpp_event_queue(u32 thread_index)
u32 timer_handle
Timeout timer handle.
#define clib_memcpy_fast(a, b, c)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static void http_static_server_sessions_writer_unlock(void)
Drop writer lock on the sessions pools.
static f64 vlib_time_now(vlib_main_t *vm)
u32 fifo_size
Size of the allocated rx, tx fifos, roughly 8K or so.
svm_fifo_t * rx_fifo
Pointers to rx/tx buffers.
static uword http_static_server_process(vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f)
Timer-wheel expiration process.
u32 data_offset
Current data send offset.
u32 private_segment_size
Private segment size, usually 0.
u32 vpp_session_index
vpp session index, handle
void session_send_rpc_evt_to_thread(u32 thread_index, void *fp, void *rpc_args)
#define hash_set_mem(h, key, value)
int debug_level
Enable debug messages.
clib_timebase_t timebase
Time base, so we can generate browser cache control http spew.
static void http_static_server_session_disconnect(http_session_t *hs)
Disconnect a session.
#define pool_is_free(P, E)
Use free bitmap to query whether given element is free.
struct _vnet_application_add_tls_cert_args_t vnet_app_add_tls_cert_args_t
void http_static_server_register_builtin_handler(void *fp, char *url, int request_type)
Register a builtin GET or POST handler.
u8 * path
Fully-resolved file path.
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
static int v_find_index(u8 *vec, char *str)
u32 prealloc_fifos
Number of preallocated fifos, usually 0.
static void http_static_server_detach_cache_entry(http_session_t *hs)
Detach cache entry from session.
clib_error_t * vnet_app_add_tls_cert(vnet_app_add_tls_cert_args_t *a)
int http_static_server_enable_api(u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, u32 private_segment_size, u8 *www_root, u8 *uri)
API helper function for vl_api_http_static_enable_t messages.
struct _vnet_bind_args_t vnet_listen_args_t
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static session_handle_t session_handle(session_t *s)
static void lru_validate(http_static_server_main_t *hsm)
Sanity-check the forward and reverse LRU lists.
void session_get_endpoint(session_t *s, transport_endpoint_t *tep, u8 is_lcl)
static void http_static_server_session_timer_stop(http_session_t *hs)
stop a session cleanup timer
svm_msg_q_t ** vpp_queue
vpp message/event queue
static int svm_fifo_is_empty(svm_fifo_t *f)
Check if fifo is empty.
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
int clib_bihash_add_del(clib_bihash *h, clib_bihash_kv *add_v, int is_add)
Add or delete a (key,value) pair from a bi-hash table.
#define VLIB_INIT_FUNCTION(x)
static int state_send_more_data(session_t *s, http_session_t *hs, http_state_machine_called_from_t cf)
static uword vlib_process_get_events(vlib_main_t *vm, uword **data_vector)
Return the first event type which has occurred and a vector of per-event data of that type...
struct _vnet_disconnect_args_t vnet_disconnect_args_t
static u32 svm_fifo_max_dequeue(svm_fifo_t *f)
Fifo max bytes to dequeue.
static int http_static_server_attach()
static const u32 test_srv_key_rsa_len
static f64 clib_timebase_now(clib_timebase_t *tb)
clib_error_t * clib_file_contents(char *file, u8 **result)
foreach_app_session_field u32 thread_index
rx thread index
#define clib_error_return(e, args...)
u8 * format_http_session_state(u8 *s, va_list *args)
u64 cache_size
Current cache size.
static int http_static_server_session_connected_callback(u32 app_index, u32 api_context, session_t *s, u8 is_fail)
static int session_rx_request(http_session_t *hs)
Retrieve data from the application layer.
int session_send_io_evt_to_thread(svm_fifo_t *f, session_evt_type_t evt_type)
format_function_t format_clib_timebase_time
#define hash_create_string(elts, value_bytes)
struct _vnet_app_attach_args_t vnet_app_attach_args_t
static void clib_spinlock_init(clib_spinlock_t *p)
u8 * format_hsm_cache_entry(u8 *s, va_list *args)
format a file cache entry
int free_data
Need to free data in detach_cache_entry.
u8 * data
Contents of the file, as a u8 * vector.
clib_error_t * vnet_app_add_tls_key(vnet_app_add_tls_key_args_t *a)
static void lru_update(http_static_server_main_t *hsm, file_data_cache_t *ep, f64 now)
Remove and re-add a cache entry from/to the LRU lists.
file_data_cache_t * cache_pool
Unified file data cache pool.
static int http_static_server_rx_tx_callback(session_t *s, http_state_machine_called_from_t cf)
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
static void clib_rwlock_init(clib_rwlock_t *p)
static int http_static_server_tx_callback(session_t *s)
static u8 * format_state_machine_called_from(u8 *s, va_list *args)
Format the called-from enum.
u8 * data
File data, a vector.
static void clib_rwlock_reader_unlock(clib_rwlock_t *p)
static int http_static_server_session_accept_callback(session_t *s)
Session accept callback.
#define pool_put(P, E)
Free an object E in pool P.
#define vec_dup(V)
Return copy of vector (no header, no alignment)
int svm_fifo_enqueue(svm_fifo_t *f, u32 len, const u8 *src)
Enqueue data to fifo.
http_state_machine_called_from_t
static void svm_fifo_unset_event(svm_fifo_t *f)
Unset fifo event flag.
static void http_expired_timers_dispatch(u32 *expired_timers)
Expired session timer-wheel callback.
uword * get_url_handlers
Hash tables for built-in GET and POST handlers.
static const char test_srv_crt_rsa[]
void clib_bihash_init(clib_bihash *h, char *name, u32 nbuckets, uword memory_size)
initialize a bounded index extensible hash table
clib_error_t * vnet_session_enable_disable(vlib_main_t *vm, u8 is_en)
static int http_static_server_rx_callback(session_t *s)
format_function_t format_ip46_address
int vnet_application_attach(vnet_app_attach_args_t *a)
Attach application to vpp.
static void http_static_server_session_lookup_del(u32 thread_index, u32 s_index)
Remove a session from the vpp < – > http session index map.
static u8 svm_fifo_set_event(svm_fifo_t *f)
Set fifo event flag.
static void clib_rwlock_writer_unlock(clib_rwlock_t *p)
f64 last_used
Last time the cache entry was used.
#define VLIB_REGISTER_NODE(x,...)
#define vec_free(V)
Free vector's memory (no header).
static clib_error_t * http_static_server_create_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
#define clib_warning(format, args...)
static void http_static_server_session_reset_callback(session_t *s)
Session reset callback.
u32 ** session_to_http_session
vpp session to http session index map
http_session_t ** sessions
Per thread vector of session pools.
static int state_established(session_t *s, http_session_t *hs, http_state_machine_called_from_t cf)
established state - waiting for GET, POST, etc.
static void http_static_server_sessions_reader_unlock(void)
Drop reader lock on the sessions pools.
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
static u32 static_send_data(http_session_t *hs, u8 *data, u32 length, u32 offset)
send http data
static const char * http_error_template
http error boilerplate
static transport_proto_t session_type_transport_proto(session_type_t st)
clib_rwlock_t sessions_lock
Session pool reader writer lock.
void clib_timebase_init(clib_timebase_t *tb, i32 timezone_offset_in_hours, clib_timebase_daylight_time_t daylight_type)
static session_cb_vft_t http_static_server_session_cb_vft
Session-layer virtual function table.
static const char test_srv_key_rsa[]
#define VLIB_CLI_COMMAND(x,...)
u32 cache_pool_index
File cache pool index.
#define uword_to_pointer(u, type)
static int state_closed(session_t *s, http_session_t *hs, http_state_machine_called_from_t cf)
Session-layer (main) data rx callback.
#define vec_delete(V, N, M)
Delete N elements starting at element M.
static void http_static_server_session_disconnect_callback(session_t *s)
Session disconnect callback.
static int http_static_server_create(vlib_main_t *vm)
static int http_static_server_listen()
struct _vnet_application_add_tls_key_args_t vnet_app_add_tls_key_args_t
enum _transport_proto transport_proto_t
u32 app_index
Application index.
#define clib_error_report(e)
static void svm_fifo_add_want_deq_ntf(svm_fifo_t *f, u8 ntf_type)
Set specific want notification flag.
u32 my_client_index
API client handle.
static void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Set node dispatch state.
Session has sent an HTML response.
static uword pointer_to_uword(const void *p)
u32 first_index
Cache LRU listheads.
Notify on transition from full.
http_builtin_method_type_t
static http_session_t * http_static_server_session_alloc(u32 thread_index)
Allocate an http session.
u8 thread_index
Index of the thread that allocated the session.
tw_timer_wheel_2t_1w_2048sl_t tw
Session cleanup timer wheel.
template key/value backing page structure
static void http_static_server_session_lookup_add(u32 thread_index, u32 s_index, u32 hs_index)
add a session to the vpp < – > http session index map
u32 next_index
Cache LRU links.
static void http_static_server_sessions_writer_lock(void)
Acquire writer lock on the sessions pools.
static const char * http_response_template
http response boilerplate
static clib_error_t * http_static_server_main_init(vlib_main_t *vm)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static clib_error_t * http_show_static_server_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
volatile u8 session_state
State in session layer state machine.
static void close_session(http_session_t *hs)
static http_session_t * http_static_server_session_get(u32 thread_index, u32 hs_index)
Get an http session by index.
static void http_static_server_session_free(http_session_t *hs)
Free an http session.
static void send_error(http_session_t *hs, char *str)
Send an http error string.
int vnet_bind_uri(vnet_listen_args_t *a)
int inuse
Reference count, so we don't recycle while referenced.
static int state_sent_ok(session_t *s, http_session_t *hs, http_state_machine_called_from_t cf)
int vnet_disconnect_session(vnet_disconnect_args_t *a)
u8 * uri
The bind URI, defaults to tcp://0.0.0.0/80.
#define hash_get_mem(h, key)
struct clib_bihash_value offset
template key/value backing page structure
static struct option options[]
static vlib_thread_main_t * vlib_get_thread_main()
vl_api_dhcp_client_state_t state
static vlib_node_t * vlib_get_node(vlib_main_t *vm, u32 i)
Get vlib node by index.
static void http_static_server_session_cleanup_cb(void *hs_handlep)
#define clib_strcmp(s1, s2)
u64 cache_evictions
Number of cache evictions.
uword * post_url_handlers
int(* session_accept_callback)(session_t *new_session)
Notify server of newly accepted session.
static size_t strnlen_s_inline(const char *s, size_t maxsize)
static int http_static_server_add_segment_callback(u32 client_index, u64 segment_handle)
In-memory file data cache entry.
void vlib_start_process(vlib_main_t *vm, uword process_index)
u8 * www_root
root path to be served
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
u64 cache_limit
Max cache size in bytes.
http_static_server_main_t http_static_server_main
static void http_static_server_sessions_reader_lock(void)
Acquire reader lock on the sessions pools.
static const u32 test_srv_crt_rsa_len
static void http_static_server_session_timer_start(http_session_t *hs)
Start a session cleanup timer.