From bd8013ee8cf3522230f413cf2b7ec0b895cd5979 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Tue, 1 Feb 2022 13:17:13 -0800 Subject: http_static: add support for async tx from handlers URL handlers can send data asynchronously if needed. Type: improvement Signed-off-by: Florin Coras Change-Id: I89eae690cb26543479c7659b5dc46604cbb22eba --- src/plugins/builtinurl/builtins.c | 49 ++++++++--------- src/plugins/http_static/builtinurl/json_urls.c | 49 ++++++++--------- src/plugins/http_static/http_static.c | 2 +- src/plugins/http_static/http_static.h | 57 ++++++++++++++++++- src/plugins/http_static/static_server.c | 76 +++++++++++++++++++------- src/plugins/mactime/builtins.c | 15 +++-- 6 files changed, 161 insertions(+), 87 deletions(-) diff --git a/src/plugins/builtinurl/builtins.c b/src/plugins/builtinurl/builtins.c index 4ebcd64888f..14b68ce4a58 100644 --- a/src/plugins/builtinurl/builtins.c +++ b/src/plugins/builtinurl/builtins.c @@ -18,8 +18,8 @@ #include #include -int -handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs) +hss_url_handler_rc_t +handle_get_version (hss_url_handler_args_t *args) { u8 *s = 0; @@ -28,11 +28,10 @@ handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs) 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; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; + return HSS_URL_HANDLER_OK; } void @@ -62,9 +61,8 @@ trim_path_from_request (u8 * s, char *path) } } -int -handle_get_interface_stats (http_req_method_t reqtype, u8 *request, - hss_session_t *hs) +hss_url_handler_rc_t +handle_get_interface_stats (hss_url_handler_args_t *args) { u8 *s = 0, *stats = 0; uword *p; @@ -80,16 +78,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request, vnet_interface_main_t *im = &vnm->interface_main; /* Get stats for a single interface via http POST */ - if (reqtype == HTTP_REQ_POST) + if (args->reqtype == HTTP_REQ_POST) { - trim_path_from_request (request, "interface_stats.json"); + trim_path_from_request (args->request, "interface_stats.json"); /* Find the sw_if_index */ - p = hash_get (im->hw_interface_by_name, request); + p = hash_get (im->hw_interface_by_name, args->request); if (!p) { s = format (s, "{\"interface_stats\": {[\n"); - s = format (s, " \"name\": \"%s\",", request); + s = format (s, " \"name\": \"%s\",", args->request); s = format (s, " \"error\": \"%s\"", "UnknownInterface"); s = format (s, "]}\n"); goto out; @@ -132,18 +130,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request, s = format (s, "]}\n"); out: - hs->data = s; - hs->data_offset = 0; - hs->cache_pool_index = ~0; - hs->free_data = 1; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; vec_free (sw_if_indices); vec_free (stats); - return 0; + return HSS_URL_HANDLER_OK; } -int -handle_get_interface_list (http_req_method_t reqtype, u8 *request, - hss_session_t *hs) +hss_url_handler_rc_t +handle_get_interface_list (hss_url_handler_args_t *args) { u8 *s = 0; int i; @@ -176,11 +172,10 @@ handle_get_interface_list (http_req_method_t reqtype, u8 *request, 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; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; + return HSS_URL_HANDLER_OK; } void diff --git a/src/plugins/http_static/builtinurl/json_urls.c b/src/plugins/http_static/builtinurl/json_urls.c index ccd70fb1799..0d83d39fade 100644 --- a/src/plugins/http_static/builtinurl/json_urls.c +++ b/src/plugins/http_static/builtinurl/json_urls.c @@ -16,8 +16,8 @@ #include #include -int -handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs) +hss_url_handler_rc_t +handle_get_version (hss_url_handler_args_t *args) { u8 *s = 0; @@ -25,11 +25,10 @@ handle_get_version (http_req_method_t reqtype, u8 *request, hss_session_t *hs) 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; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; + return HSS_URL_HANDLER_OK; } void @@ -59,9 +58,8 @@ trim_path_from_request (u8 *s, char *path) } } -int -handle_get_interface_stats (http_req_method_t reqtype, u8 *request, - hss_session_t *hs) +hss_url_handler_rc_t +handle_get_interface_stats (hss_url_handler_args_t *args) { u8 *s = 0, *stats = 0; uword *p; @@ -77,16 +75,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request, vnet_interface_main_t *im = &vnm->interface_main; /* Get stats for a single interface via http POST */ - if (reqtype == HTTP_REQ_POST) + if (args->reqtype == HTTP_REQ_POST) { - trim_path_from_request (request, "interface_stats.json"); + trim_path_from_request (args->request, "interface_stats.json"); /* Find the sw_if_index */ - p = hash_get (im->hw_interface_by_name, request); + p = hash_get (im->hw_interface_by_name, args->request); if (!p) { s = format (s, "{\"interface_stats\": {[\n"); - s = format (s, " \"name\": \"%s\",", request); + s = format (s, " \"name\": \"%s\",", args->request); s = format (s, " \"error\": \"%s\"", "UnknownInterface"); s = format (s, "]}\n"); goto out; @@ -127,18 +125,16 @@ handle_get_interface_stats (http_req_method_t reqtype, u8 *request, s = format (s, "]}\n"); out: - hs->data = s; - hs->data_offset = 0; - hs->cache_pool_index = ~0; - hs->free_data = 1; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; vec_free (sw_if_indices); vec_free (stats); - return 0; + return HSS_URL_HANDLER_OK; } -int -handle_get_interface_list (http_req_method_t reqtype, u8 *request, - hss_session_t *hs) +hss_url_handler_rc_t +handle_get_interface_list (hss_url_handler_args_t *args) { u8 *s = 0; int i; @@ -169,11 +165,10 @@ handle_get_interface_list (http_req_method_t reqtype, u8 *request, 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; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; + return HSS_URL_HANDLER_OK; } void diff --git a/src/plugins/http_static/http_static.c b/src/plugins/http_static/http_static.c index b8d6931b4c6..4afe42291db 100644 --- a/src/plugins/http_static/http_static.c +++ b/src/plugins/http_static/http_static.c @@ -33,7 +33,7 @@ #include __clib_export void -hss_register_url_handler (hss_url_handler_t fp, const char *url, +hss_register_url_handler (hss_url_handler_fn fp, const char *url, http_req_method_t request_type) { hss_main_t *hsm = &hss_main; diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h index 05d6ee05a4c..d3fa29b068d 100644 --- a/src/plugins/http_static/http_static.h +++ b/src/plugins/http_static/http_static.h @@ -40,8 +40,10 @@ typedef struct session_handle_t vpp_session_handle; /** Fully-resolved file path */ u8 *path; - /** File data, a vector */ + /** Data to send */ u8 *data; + /** Data length */ + u32 data_len; /** Current data send offset */ u32 data_offset; /** Need to free data in detach_cache_entry */ @@ -50,6 +52,21 @@ typedef struct u32 cache_pool_index; } hss_session_t; +typedef struct hss_session_handle_ +{ + union + { + struct + { + u32 session_index; + u32 thread_index; + }; + u64 as_u64; + }; +} hss_session_handle_t; + +STATIC_ASSERT_SIZEOF (hss_session_handle_t, sizeof (u64)); + /** \brief In-memory file data cache entry */ typedef struct @@ -67,7 +84,40 @@ typedef struct int inuse; } hss_cache_entry_t; -typedef int (*hss_url_handler_t) (http_req_method_t, u8 *, hss_session_t *); +typedef struct hss_url_handler_args_ +{ + hss_session_handle_t sh; + + union + { + /* Request args */ + struct + { + u8 *request; + http_req_method_t reqtype; + }; + + /* Reply args */ + struct + { + u8 *data; + uword data_len; + u8 free_vec_data; + http_status_code_t sc; + }; + }; +} hss_url_handler_args_t; + +typedef enum hss_url_handler_rc_ +{ + HSS_URL_HANDLER_OK, + HSS_URL_HANDLER_ERROR, + HSS_URL_HANDLER_ASYNC, +} hss_url_handler_rc_t; + +typedef hss_url_handler_rc_t (*hss_url_handler_fn) (hss_url_handler_args_t *); +typedef void (*hss_register_url_fn) (hss_url_handler_fn, char *, int); +typedef void (*hss_session_send_fn) (hss_url_handler_args_t *args); /** \brief Main data structure */ @@ -139,8 +189,9 @@ int hss_create (vlib_main_t *vm); /** * Register a GET or POST URL handler */ -void hss_register_url_handler (hss_url_handler_t fp, const char *url, +void hss_register_url_handler (hss_url_handler_fn fp, const char *url, http_req_method_t type); +void hss_session_send_data (hss_url_handler_args_t *args); 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 a78b5fe4f2b..a9b3fdbb08a 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -257,9 +257,9 @@ start_send_data (hss_session_t *hs, http_status_code_t status) msg.type = HTTP_MSG_REPLY; msg.code = status; msg.content_type = HTTP_CONTENT_TEXT_HTML; - msg.data.len = vec_len (hs->data); + msg.data.len = hs->data_len; - if (vec_len (hs->data) > hss_main.use_ptr_thresh) + if (hs->data_len > hss_main.use_ptr_thresh) { msg.data.type = HTTP_MSG_DATA_PTR; rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg); @@ -280,9 +280,9 @@ start_send_data (hss_session_t *hs, http_status_code_t status) if (!msg.data.len) goto done; - rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (hs->data), hs->data); + rv = svm_fifo_enqueue (ts->tx_fifo, hs->data_len, hs->data); - if (rv != vec_len (hs->data)) + if (rv != hs->data_len) { hs->data_offset = rv; svm_fifo_add_want_deq_ntf (ts->tx_fifo, SVM_FIFO_WANT_DEQ_NOTIF); @@ -294,12 +294,25 @@ done: session_send_io_evt_to_thread (ts->tx_fifo, SESSION_IO_EVT_TX); } +__clib_export void +hss_session_send_data (hss_url_handler_args_t *args) +{ + hss_session_t *hs; + + hs = hss_session_get (args->sh.thread_index, args->sh.session_index); + hs->data = args->data; + hs->data_len = args->data_len; + hs->free_data = args->free_vec_data; + start_send_data (hs, args->sc); +} + 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) + u8 *request) { + http_status_code_t sc = HTTP_STATUS_OK; + hss_url_handler_args_t args = {}; uword *p, *url_table; - hss_url_handler_t fp; int rv; if (!hsm->enable_url_handlers) @@ -313,24 +326,45 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, if (!p) return -1; + hs->path = 0; + hs->data_offset = 0; + hs->cache_pool_index = ~0; + 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) + args.reqtype = rt; + args.request = request; + args.sh.thread_index = hs->thread_index; + args.sh.session_index = hs->session_index; + + rv = ((hss_url_handler_fn) p[0]) (&args); + + /* Wait for data from handler */ + if (rv == HSS_URL_HANDLER_ASYNC) + return 0; + + if (rv == HSS_URL_HANDLER_ERROR) { 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; + sc = HTTP_STATUS_NOT_FOUND; } + hs->data = args.data; + hs->data_len = args.data_len; + hs->free_data = args.free_vec_data; + + start_send_data (hs, sc); + + if (!hs->data) + hss_session_disconnect_transport (hs); + return 0; } static int -find_data (hss_session_t *hs, http_req_method_t rt, u8 *request) +handle_request (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; @@ -338,8 +372,8 @@ find_data (hss_session_t *hs, http_req_method_t rt, u8 *request) clib_error_t *error; u8 *path; - if (!try_url_handler (hsm, hs, rt, request, &sc)) - goto done; + if (!try_url_handler (hsm, hs, rt, request)) + return 0; /* * Construct the file to open @@ -541,6 +575,10 @@ find_data (hss_session_t *hs, http_req_method_t rt, u8 *request) done: + start_send_data (hs, sc); + if (!hs->data) + hss_session_disconnect_transport (hs); + return sc; } @@ -551,7 +589,6 @@ hss_ts_rx_callback (session_t *ts) u8 *request = 0; http_msg_t msg; int rv; - http_status_code_t sc; hs = hss_session_get (ts->thread_index, ts->opaque); @@ -573,12 +610,9 @@ hss_ts_rx_callback (session_t *ts) ASSERT (rv == msg.data.len); /* Find and send data */ - sc = find_data (hs, msg.method_type, request); - start_send_data (hs, sc); + handle_request (hs, msg.method_type, request); vec_free (request); - if (!hs->data) - hss_session_disconnect_transport (hs); return 0; } @@ -594,7 +628,7 @@ hss_ts_tx_callback (session_t *ts) if (!hs || !hs->data) return 0; - to_send = vec_len (hs->data) - hs->data_offset; + to_send = hs->data_len - hs->data_offset; rv = svm_fifo_enqueue (ts->tx_fifo, to_send, hs->data + hs->data_offset); if (rv <= 0) @@ -982,7 +1016,7 @@ format_hss_session (u8 *s, va_list *args) int __clib_unused verbose = va_arg (*args, int); s = format (s, "\n path %s, data length %u, data_offset %u", - hs->path ? hs->path : (u8 *) "[none]", vec_len (hs->data), + hs->path ? hs->path : (u8 *) "[none]", hs->data_len, hs->data_offset); return s; } diff --git a/src/plugins/mactime/builtins.c b/src/plugins/mactime/builtins.c index d039f7bff7f..c487d0375bf 100644 --- a/src/plugins/mactime/builtins.c +++ b/src/plugins/mactime/builtins.c @@ -14,8 +14,8 @@ mactime_ip_neighbor_copy (index_t ipni, void *ctx) return (WALK_CONTINUE); } -static int -handle_get_mactime (http_req_method_t reqtype, u8 *request, hss_session_t *hs) +static hss_url_handler_rc_t +handle_get_mactime (hss_url_handler_args_t *args) { mactime_main_t *mm = &mactime_main; mactime_device_t *dp; @@ -145,17 +145,16 @@ handle_get_mactime (http_req_method_t reqtype, u8 *request, hss_session_t *hs) vec_free (macstring); vec_free (pool_indices); - hs->data = s; - hs->data_offset = 0; - hs->cache_pool_index = ~0; - hs->free_data = 1; - return 0; + args->data = s; + args->data_len = vec_len (s); + args->free_vec_data = 1; + return HSS_URL_HANDLER_OK; } void mactime_url_init (vlib_main_t * vm) { - void (*fp) (void *, char *, int); + hss_register_url_fn fp; /* Look up the builtin URL registration handler */ fp = vlib_get_plugin_symbol ("http_static_plugin.so", -- cgit 1.2.3-korg