diff options
author | 2025-03-28 12:04:50 -0400 | |
---|---|---|
committer | 2025-03-28 20:28:15 +0000 | |
commit | 2926d0a88ef1aca5f758fb4ab68aaab45947479b (patch) | |
tree | d04e465bc8c4696fad746fec65b8215eff40d8a1 | |
parent | cf8deb94a22aa0df5d84f14f42fa35d3c9611ec1 (diff) |
http_static: POST to static files improvement
Type: improvement
Change-Id: I6a6794dee3c9e948227e6c08769d45aa595bfe02
Signed-off-by: Matus Fabian <matfabia@cisco.com>
-rw-r--r-- | extras/scripts/host-stack/http-speed-test/speed_test_startup_conf | 31 | ||||
-rw-r--r-- | extras/scripts/host-stack/http-speed-test/speedtest.cli | 5 | ||||
-rw-r--r-- | src/plugins/http/http.c | 7 | ||||
-rw-r--r-- | src/plugins/http/http1.c | 10 | ||||
-rw-r--r-- | src/plugins/http/http_private.h | 2 | ||||
-rw-r--r-- | src/plugins/http_static/http_static.h | 8 | ||||
-rw-r--r-- | src/plugins/http_static/static_server.c | 147 |
7 files changed, 156 insertions, 54 deletions
diff --git a/extras/scripts/host-stack/http-speed-test/speed_test_startup_conf b/extras/scripts/host-stack/http-speed-test/speed_test_startup_conf new file mode 100644 index 00000000000..ec9230148e5 --- /dev/null +++ b/extras/scripts/host-stack/http-speed-test/speed_test_startup_conf @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Cisco Systems, Inc. +unix { + interactive log /tmp/vpp.log + full-coredump + exec /scratch/matfabia/vpp/extras/scripts/host-stack/http-speed-test/speedtest.cli + cli-listen /run/vpp/cli.sock + poll-sleep-usec 0 +} +heapsize 4g +api-trace { on } +api-segment { global-size 2000M api-size 1G gid vpp } +dpdk { + dev 0000:17:00.0 { + num-tx-desc 256 + num-rx-desc 512 + num-rx-queues 1 + tso on + } + enable-tcp-udp-checksum +} +cpu { + skip-cores 0 + main-core 1 + corelist-workers 2-10 +} +buffers { buffers-per-numa 16536 } +session { event-queue-length 100000 use-app-socket-api } +tcp { max-rx-fifo 128m tso } +socksvr { socket-name /run/vpp-api.sock } + diff --git a/extras/scripts/host-stack/http-speed-test/speedtest.cli b/extras/scripts/host-stack/http-speed-test/speedtest.cli new file mode 100644 index 00000000000..555aa173d6b --- /dev/null +++ b/extras/scripts/host-stack/http-speed-test/speedtest.cli @@ -0,0 +1,5 @@ +comment {SPDX-License-Identifier: Apache-2.0} +comment {Copyright (c) 2025 Cisco Systems, Inc.} +set int ip address HundredGigabitEthernet17/0/0 6.0.1.1/24 +set int state HundredGigabitEthernet17/0/0 up +http static server www-root /scratch/matfabia/Speed-Test max-body-size 40m max-age 0 keepalive-timeout 120 cache-size 100m fifo-size 512k diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index 5998a9ebd18..43b0993e462 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -525,7 +525,7 @@ http_ts_disconnect_callback (session_t *ts) hc_handle.as_u32 = ts->opaque; - HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index); + HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_handle.conn_index); hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); @@ -543,7 +543,7 @@ http_ts_reset_callback (session_t *ts) hc_handle.as_u32 = ts->opaque; - HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_index); + HTTP_DBG (1, "hc [%u]%x", ts->thread_index, hc_handle.conn_index); hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); @@ -607,7 +607,8 @@ http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf) hc_handle.as_u32 = ts->opaque; hc = http_conn_get_w_thread (hc_handle.conn_index, ts->thread_index); - HTTP_DBG (1, "going to free hc [%u]%x", ts->thread_index, hc_index); + HTTP_DBG (1, "going to free hc [%u]%x", ts->thread_index, + hc_handle.conn_index); if (!(hc->flags & HTTP_CONN_F_PENDING_TIMER)) http_conn_timer_stop (hc); diff --git a/src/plugins/http/http1.c b/src/plugins/http/http1.c index ec118aa4e52..258330e87ba 100644 --- a/src/plugins/http/http1.c +++ b/src/plugins/http/http1.c @@ -1859,10 +1859,12 @@ http1_transport_rx_callback (http_conn_t *hc) if (!http1_req_state_is_rx_valid (req)) { - clib_warning ("hc [%u]%x invalid rx state: http req state " - "'%U', session state '%U'", - hc->c_thread_index, hc->hc_hc_index, format_http_req_state, - req->state, format_http_conn_state, hc); + if (http_io_ts_max_read (hc)) + clib_warning ("hc [%u]%x invalid rx state: http req state " + "'%U', session state '%U'", + hc->c_thread_index, hc->hc_hc_index, + format_http_req_state, req->state, + format_http_conn_state, hc); http_io_ts_drain_all (hc); return; } diff --git a/src/plugins/http/http_private.h b/src/plugins/http/http_private.h index ebec59aeaee..8354bf29289 100644 --- a/src/plugins/http/http_private.h +++ b/src/plugins/http/http_private.h @@ -691,7 +691,7 @@ http_conn_accept_request (http_conn_t *hc, http_req_t *req) int rv; HTTP_DBG (1, "hc [%u]%x req %x", hc->hc_hc_index, hc->c_thread_index, - req->hr_req_index); + req->hr_req_handle); /* allocate app session and initialize */ as = session_alloc (hc->c_thread_index); diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h index e158a32dbc9..2b6de03c71a 100644 --- a/src/plugins/http_static/http_static.h +++ b/src/plugins/http_static/http_static.h @@ -33,7 +33,7 @@ /** \brief Application session */ -typedef struct +typedef struct hss_session_ { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); u32 session_index; @@ -42,6 +42,9 @@ typedef struct /** vpp session index, handle */ u32 vpp_session_index; session_handle_t vpp_session_handle; + u8 *target_path; + u8 *target_query; + http_req_method_t rt; /** Fully-resolved file path */ u8 *path; /** Data to send */ @@ -58,6 +61,9 @@ typedef struct http_headers_ctx_t resp_headers; /** Response header buffer */ u8 *headers_buf; + /** POST body left to receive */ + u64 left_recv; + int (*read_body_handler) (struct hss_session_ *hs, session_t *ts); } hss_session_t; typedef struct hss_session_handle_ diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index d7958fd3f1f..75481f840b2 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -30,6 +30,8 @@ #define HSS_HEADER_BUF_MAX_SIZE 16192 hss_main_t hss_main; +static int file_handler_discard_body (hss_session_t *hs, session_t *ts); + static int hss_add_header (hss_session_t *hs, http_header_name_t name, const char *value, uword value_len) @@ -280,14 +282,18 @@ content_type_from_request (u8 *request) } static int -try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, - u8 *target_path, u8 *target_query, u8 *data) +try_url_handler (hss_session_t *hs) { + hss_main_t *hsm = &hss_main; http_status_code_t sc = HTTP_STATUS_OK; hss_url_handler_args_t args = {}; uword *p, *url_table; + session_t *ts; + u8 *data = 0, *target_path; int rv; + target_path = hs->target_path; + if (!hsm->enable_url_handlers || !target_path) return -1; @@ -299,28 +305,48 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, /* Look for built-in GET / POST handlers */ url_table = - (rt == HTTP_REQ_GET) ? hsm->get_url_handlers : hsm->post_url_handlers; + (hs->rt == HTTP_REQ_GET) ? hsm->get_url_handlers : hsm->post_url_handlers; p = hash_get_mem (url_table, target_path); if (!p) return -1; + /* Read request body */ + if (hs->left_recv) + { + ts = session_get (hs->vpp_session_index, hs->thread_index); + /* TODO: add support for large content (use hs->read_body_handler) */ + if (svm_fifo_max_dequeue (ts->rx_fifo) < hs->left_recv) + { + hs->left_recv = 0; + start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR); + hss_session_disconnect_transport (hs); + return 0; + } + vec_validate (data, hs->left_recv - 1); + rv = svm_fifo_dequeue (ts->rx_fifo, hs->left_recv, data); + ASSERT (rv == hs->left_recv); + hs->left_recv = 0; + } + 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", + clib_warning ("%s '%s'", (hs->rt == HTTP_REQ_GET) ? "GET" : "POST", target_path); - args.req_type = rt; - args.query = target_query; + args.req_type = hs->rt; + args.query = hs->target_query; args.req_data = data; args.sh.thread_index = hs->thread_index; args.sh.session_index = hs->session_index; rv = ((hss_url_handler_fn) p[0]) (&args); + vec_free (data); + /* Wait for data from handler */ if (rv == HSS_URL_HANDLER_ASYNC) return 0; @@ -328,7 +354,7 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, 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", target_path); + (hs->rt == HTTP_REQ_GET) ? "GET" : "POST", target_path); sc = HTTP_STATUS_BAD_GATEWAY; } @@ -429,32 +455,49 @@ try_index_file (hss_main_t *hsm, hss_session_t *hs, u8 *path) } static int -try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, - u8 *target) +try_file_handler (hss_session_t *hs) { + hss_main_t *hsm = &hss_main; http_status_code_t sc = HTTP_STATUS_OK; u8 *path, *sanitized_path; - u32 ce_index; + u32 ce_index, max_dequeue; http_content_type_t type; u8 *last_modified; + session_t *ts; /* Feature not enabled */ if (!hsm->www_root) return -1; + /* Discard request body */ + if (hs->left_recv) + { + ts = session_get (hs->vpp_session_index, hs->thread_index); + max_dequeue = svm_fifo_max_dequeue (ts->rx_fifo); + if (max_dequeue < hs->left_recv) + { + svm_fifo_dequeue_drop (ts->rx_fifo, max_dequeue); + hs->left_recv -= max_dequeue; + hs->read_body_handler = file_handler_discard_body; + return 0; + } + svm_fifo_dequeue_drop (ts->rx_fifo, hs->left_recv); + hs->left_recv = 0; + } + /* Sanitize received path */ - sanitized_path = http_path_sanitize (target); + sanitized_path = http_path_sanitize (hs->target_path); /* * Construct the file to open */ - if (!target) + if (!sanitized_path) path = format (0, "%s%c", hsm->www_root, 0); else path = format (0, "%s/%s%c", hsm->www_root, sanitized_path, 0); if (hsm->debug_level > 0) - clib_warning ("%s '%s'", (rt == HTTP_REQ_GET) ? "GET" : "POST", path); + clib_warning ("%s '%s'", (hs->rt == HTTP_REQ_GET) ? "GET" : "POST", path); if (hs->data && hs->free_data) vec_free (hs->data); @@ -498,7 +541,7 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, * Cache-Control max-age * Last-Modified */ - type = content_type_from_request (target); + type = content_type_from_request (sanitized_path); if (hss_add_header (hs, HTTP_HEADER_CONTENT_TYPE, http_content_type_token (type)) || hss_add_header (hs, HTTP_HEADER_CACHE_CONTROL, @@ -520,15 +563,12 @@ done: } static void -handle_request (hss_session_t *hs, http_req_method_t rt, u8 *target_path, - u8 *target_query, u8 *data) +handle_request (hss_session_t *hs) { - hss_main_t *hsm = &hss_main; - - if (!try_url_handler (hsm, hs, rt, target_path, target_query, data)) + if (!try_url_handler (hs)) return; - if (!try_file_handler (hsm, hs, rt, target_path)) + if (!try_file_handler (hs)) return; /* Handler did not find anything return 404 */ @@ -537,19 +577,41 @@ handle_request (hss_session_t *hs, http_req_method_t rt, u8 *target_path, } static int +file_handler_discard_body (hss_session_t *hs, session_t *ts) +{ + u32 max_dequeue, to_discard; + + max_dequeue = svm_fifo_max_dequeue (ts->rx_fifo); + to_discard = clib_min (max_dequeue, hs->left_recv); + svm_fifo_dequeue_drop (ts->rx_fifo, to_discard); + hs->left_recv -= to_discard; + if (hs->left_recv == 0) + return try_file_handler (hs); + return 0; +} + +static int hss_ts_rx_callback (session_t *ts) { hss_main_t *hsm = &hss_main; hss_session_t *hs; - u8 *target_path = 0, *target_query = 0, *data = 0; http_msg_t msg; int rv; hs = hss_session_get (ts->thread_index, ts->opaque); + if (hs->left_recv != 0) + { + ASSERT (hs->read_body_handler); + return hs->read_body_handler (hs, ts); + } + if (hs->free_data) vec_free (hs->data); + hs->data = 0; hs->data_len = 0; + vec_free (hs->target_path); + vec_free (hs->target_query); http_init_headers_ctx (&hs->resp_headers, hs->headers_buf, vec_len (hs->headers_buf)); @@ -567,37 +629,38 @@ hss_ts_rx_callback (session_t *ts) goto err_done; } + hs->rt = msg.method_type; + /* Read target path */ if (msg.data.target_path_len) { - vec_validate (target_path, msg.data.target_path_len - 1); + vec_validate (hs->target_path, msg.data.target_path_len - 1); rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset, - msg.data.target_path_len, target_path); + msg.data.target_path_len, hs->target_path); ASSERT (rv == msg.data.target_path_len); - if (http_validate_abs_path_syntax (target_path, 0)) + if (http_validate_abs_path_syntax (hs->target_path, 0)) { start_send_data (hs, HTTP_STATUS_BAD_REQUEST); goto err_done; } /* Target path must be a proper C-string in addition to a vector */ - vec_add1 (target_path, 0); + vec_add1 (hs->target_path, 0); } /* Read target query */ if (msg.data.target_query_len) { - vec_validate (target_query, msg.data.target_query_len - 1); + vec_validate (hs->target_query, msg.data.target_query_len - 1); rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_query_offset, - msg.data.target_query_len, target_query); + msg.data.target_query_len, hs->target_query); ASSERT (rv == msg.data.target_query_len); - if (http_validate_query_syntax (target_query, 0)) + if (http_validate_query_syntax (hs->target_query, 0)) { start_send_data (hs, HTTP_STATUS_BAD_REQUEST); goto err_done; } } - /* Read request body for POST requests */ if (msg.data.body_len && msg.method_type == HTTP_REQ_POST) { if (msg.data.body_len > hsm->max_body_size) @@ -605,28 +668,19 @@ hss_ts_rx_callback (session_t *ts) start_send_data (hs, HTTP_STATUS_CONTENT_TOO_LARGE); goto err_done; } - if (svm_fifo_max_dequeue (ts->rx_fifo) - msg.data.body_offset < - msg.data.body_len) - { - start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR); - goto err_done; - } - vec_validate (data, msg.data.body_len - 1); - rv = svm_fifo_peek (ts->rx_fifo, msg.data.body_offset, msg.data.body_len, - data); - ASSERT (rv == msg.data.body_len); + + hs->left_recv = msg.data.body_len; + /* drop everything up to body */ + svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset); } /* Find and send data */ - handle_request (hs, msg.method_type, target_path, target_query, data); + handle_request (hs); goto done; err_done: hss_session_disconnect_transport (hs); done: - vec_free (target_path); - vec_free (target_query); - vec_free (data); svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.len); return 0; } @@ -757,6 +811,8 @@ hss_ts_cleanup (session_t *s, session_cleanup_ntf_t ntf) hs->free_data = 0; vec_free (hs->headers_buf); vec_free (hs->path); + vec_free (hs->target_path); + vec_free (hs->target_query); hss_session_free (hs); } @@ -952,8 +1008,9 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, else 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 %d", &hsm->fifo_size)) - hsm->fifo_size <<= 10; + 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)) ; |