21 #include <sys/types.h> 44 char *
which =
"bogus!";
62 s =
format (s,
"%s", which);
113 (&http_static_server_main.
tw, hs_handle, 0, 60);
126 tw_timer_stop_2t_1w_2048sl (&http_static_server_main.
tw, hs->
timer_handle);
141 hs->session_index = hs - hsm->
sessions[thread_index];
172 u32 save_thread_index;
175 memset (hs, 0xfa,
sizeof (*hs));
256 a->app_index = http_static_server_main.
app_index;
266 "Content-Type: text/html\r\n" 267 "Connection: close\r\n" 268 "Pragma: no-cache\r\n" 269 "Content-Length: 0\r\n\r\n";
275 "Expires: %U GMT\r\n" 276 "Server: VPP Static\r\n" 277 "Content-Type: %s\r\n" 278 "Content-Length: %d\r\n\r\n";
296 bytes_to_send = length -
offset;
298 while (bytes_to_send > 0)
303 (hs->tx_fifo, bytes_to_send, data + offset);
306 if (actual_transfer <= 0)
309 clib_warning (
"WARNING: still %d bytes to send", bytes_to_send);
314 offset += actual_transfer;
315 bytes_to_send -= actual_transfer;
318 clib_warning (
"WARNING: still %d bytes to send", bytes_to_send);
352 u32 max_dequeue, cursize;
363 ASSERT (n_read == max_dequeue);
367 _vec_len (hs->
rx_buf) = cursize + n_read;
382 last_timestamp = 1e70;
383 for (i = 1, index = hsm->
first_index; index != ~0;)
390 clib_warning (
"%d[%d]: last used %.6f, last_timestamp %.6f",
398 last_timestamp = 0.0;
399 for (i = 1, index = hsm->
last_index; index != ~0;)
406 clib_warning (
"%d[%d]: last used %.6f, last_timestamp %.6f",
511 clib_warning (
"WARNING: http session %d, called from %U",
525 (
void *fp,
char *url,
int request_type)
528 uword *p, *builtin_table;
537 clib_warning (
"WARNING: attempt to replace handler for %s '%s' ignored",
539 "GET" :
"POST", url);
567 for (start_index = 0; start_index < (vlen - slen); start_index++)
569 if (!memcmp (vec, str, slen))
586 struct stat _sb, *sb = &_sb;
590 uword *p, *builtin_table;
626 vec_delete (request, i + 5 + request_type, 0);
629 for (i = 0; i <
vec_len (request); i++)
631 if (request[i] ==
' ' || request[i] ==
'?')
633 save_byte = request[
i];
643 if (request[0] ==
'/')
650 "GET" :
"POST", path);
659 request[
i] = save_byte;
667 rv = (*fp) (request_type,
request, hs);
670 clib_warning (
"builtin handler %llx hit on %s '%s' but failed!",
672 "GET" :
"POST", request);
692 if (stat ((
char *) path, sb) < 0
694 || (sb->st_mode & S_IFMT) != S_IFREG )
698 _vec_len (path) -= 1;
699 path =
format (path,
"index.html%c", 0);
700 if (stat ((
char *) path, sb) < 0
702 || (sb->st_mode & S_IFMT) != S_IFREG )
704 _vec_len (path) = save_length;
705 path =
format (path,
"/index.html%c", 0);
708 if (stat ((
char *) path, sb) < 0
710 || (sb->st_mode & S_IFMT) != S_IFREG )
735 local_port = clib_net_to_host_u16 (endpoint.port);
739 if ((proto == TRANSPORT_PROTO_TCP && local_port != 80)
740 || (proto == TRANSPORT_PROTO_TLS && local_port != 443))
743 port_str =
format (0,
":%u", (
u32) local_port);
746 redirect =
format (0,
"HTTP/1.1 301 Moved Permanently\r\n" 747 "Location: http%s://%U%s%s\r\n\r\n",
748 proto == TRANSPORT_PROTO_TLS ?
"s" :
"",
751 print_port ? port_str : (
u8 *)
"", path);
771 BVT (clib_bihash_kv) kv;
778 if (BV (clib_bihash_search) (&hsm->name_to_data, &kv, &kv) == 0)
781 clib_warning (
"lookup '%s' returned %lld", kv.key, kv.value);
803 while (free_index != ~0)
851 memset (dp, 0,
sizeof (*dp));
921 while ((
u8 *) suffix >= hs->
path && *suffix !=
'.')
924 http_type =
"text/html";
926 http_type =
"text/css";
928 http_type =
"text/javascript";
930 http_type =
"application/json";
945 http_response =
format (0, http_response_template,
952 if (offset !=
vec_len (http_response))
990 clib_warning (
"No http session for thread %d session_index %d",
999 fp = state_funcs[hs->session_state];
1000 rv = (*fp) (s, hs, cf);
1002 goto session_closed;
1130 .session_disconnect_callback =
1148 u32 segment_size = 128 << 20;
1156 a->api_client_index = ~0;
1157 a->name =
format (0,
"test_http_static_server");
1179 a_cert->app_index = a->app_index;
1185 a_key->app_index = a->app_index;
1200 a->uri =
"tcp://0.0.0.0/80";
1202 a->uri = (
char *) hsm->
uri;
1218 hs_handle >> 24, hs_handle & 0x00FFFFFF, hs);
1233 for (i = 0; i <
vec_len (expired_timers); i++)
1236 hs_handle = expired_timers[
i] & 0x7FFFFFFF;
1250 f64 now, timeout = 1.0;
1251 uword *event_data = 0;
1252 uword __clib_unused event_type;
1262 tw_timer_expire_timers_2t_1w_2048sl (&hsm->
tw, now);
1275 .name =
"static-http-server-process",
1276 .state = VLIB_NODE_STATE_DISABLED,
1317 VLIB_NODE_STATE_POLLING);
1318 n =
vlib_get_node (vm, http_static_server_process_node.index);
1329 u32 private_segment_size,
1330 u8 * www_root,
u8 * uri)
1343 return VNET_API_ERROR_INVALID_VALUE;
1346 return VNET_API_ERROR_APP_ALREADY_ATTACHED;
1358 return VNET_API_ERROR_INIT_FAILED;
1386 if (
unformat (line_input,
"www-root %s", &www_root))
1391 else if (
unformat (line_input,
"private-segment-size %U",
1394 if (seg_size >= 0x100000000ULL)
1410 "cache-size must be at least 128kb");
1414 else if (
unformat (line_input,
"uri %s", &hsm->
uri))
1418 else if (
unformat (line_input,
"debug"))
1469 .path =
"http static server",
1470 .short_help =
"http static server www-root <path> [prealloc-fifos <nn>]\n" 1471 "[private-segment-size <nnMG>] [fifo-size <nbytes>] [uri <uri>]\n" 1483 f64 now = va_arg (*args,
f64);
1488 s =
format (s,
"%40s%12s%20s",
"File",
"Size",
"Age");
1500 char *state_string =
"bogus!";
1505 state_string =
"closed";
1508 state_string =
"established";
1511 state_string =
"ok sent";
1514 state_string =
"send more data";
1520 return format (s,
"%s", state_string);
1527 int verbose = va_arg (*args,
int);
1529 s =
format (s,
"[%d]: state %U", hs->session_index,
1533 s =
format (s,
"\n path %s, data length %u, data_offset %u",
1549 int show_sessions = 0;
1558 if (
unformat (input,
"verbose %d", &verbose))
1560 else if (
unformat (input,
"verbose"))
1562 else if (
unformat (input,
"cache"))
1564 else if (
unformat (input,
"sessions"))
1570 if ((show_cache + show_sessions) == 0)
1578 (vm,
"www_root %s, cache size %lld bytes, limit %lld bytes, " 1604 u32 *session_indices = 0;
1619 for (j = 0; j <
vec_len (session_indices); j++)
1623 (hsm->
sessions[i], session_indices[j]),
1647 .path =
"show http static server",
1648 .short_help =
"show http static server sessions cache [verbose [<nn>]]",
1662 BVT (clib_bihash_kv) kv;
1671 while (free_index != ~0)
1702 vlib_cli_output (vm,
"Note: %d busy items still in cache...", busy_items);
1722 .path =
"clear http static cache",
1723 .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 http server definitions.
#define pool_foreach(VAR, POOL)
Iterate through pool.
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.
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
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
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)
static void http_static_session_cleanup(session_t *s, session_cleanup_ntf_t ntf)
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)
static int http_static_server_session_connected_callback(u32 app_index, u32 api_context, session_t *s, session_error_t err)
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.
static_always_inline uword os_get_numa_index(void)
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)
description fragment has unexpected format
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 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)
static void http_static_server_session_close_cb(void *hs_handlep)
__clib_export clib_error_t * clib_file_contents(char *file, u8 **result)
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.
#define pool_get_aligned_zero_numa(P, E, A, Z, S)
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.
vl_api_address_t endpoint
#define VLIB_REGISTER_NODE(x,...)
__clib_export void clib_timebase_init(clib_timebase_t *tb, i32 timezone_offset_in_hours, clib_timebase_daylight_time_t daylight_type, clib_time_t *clib_time)
sll srl srl sll sra u16x4 i
#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.
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.
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
#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.
__clib_export void http_static_server_register_builtin_handler(void *fp, char *url, int request_type)
Register a builtin GET or POST handler.
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.
static vlib_main_t * vlib_get_main(void)
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.
enum session_error_ session_error_t
#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
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.