From c3bbeb93b8eb5df1a15ae8babd07b01121403874 Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Wed, 23 Apr 2025 09:54:45 -0400 Subject: [PATCH] http_static: url handler buffer large POST body Add support to handle larger POST body in url handler using tx_buff, member of hss_session_t, with configurable limit. Add hss_confirm_data_read which notify http transport when body data is read and transport requested notification (e.g. used by h2 flow control). Remove old deprecated api (v2 and v3). Type: improvement Change-Id: I62640bb9cb851cb567b8176bf01f02c63257ecb9 Signed-off-by: Matus Fabian --- extras/hs-test/http_test.go | 23 +++++- src/plugins/http_static/http_static.api | 47 +++--------- src/plugins/http_static/http_static.c | 47 ++++-------- src/plugins/http_static/http_static.h | 7 ++ src/plugins/http_static/http_static_test.c | 112 +++++------------------------ src/plugins/http_static/static_server.c | 102 ++++++++++++++++++++------ test/asf/test_http_static.py | 2 +- 7 files changed, 150 insertions(+), 190 deletions(-) diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 5fec25a1feb..b9fcd39b0ff 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -28,7 +28,7 @@ func init() { RegisterNoTopoTests(HeaderServerTest, HttpPersistentConnectionTest, HttpPipeliningTest, HttpStaticMovedTest, HttpStaticNotFoundTest, HttpCliMethodNotAllowedTest, HttpAbsoluteFormUriTest, HttpCliBadRequestTest, HttpStaticBuildInUrlGetIfStatsTest, HttpStaticBuildInUrlPostIfStatsTest, - HttpInvalidRequestLineTest, HttpMethodNotImplementedTest, HttpInvalidHeadersTest, + HttpInvalidRequestLineTest, HttpMethodNotImplementedTest, HttpInvalidHeadersTest, HttpStaticPostTest, HttpContentLengthTest, HttpStaticBuildInUrlGetIfListTest, HttpStaticBuildInUrlGetVersionTest, HttpStaticMacTimeTest, HttpStaticBuildInUrlGetVersionVerboseTest, HttpVersionNotSupportedTest, HttpInvalidContentLengthTest, HttpInvalidTargetSyntaxTest, HttpStaticPathSanitizationTest, HttpUriDecodeTest, @@ -229,6 +229,27 @@ func HttpPipeliningTest(s *NoTopoSuite) { s.AssertMatchError(err, os.ErrDeadlineExceeded, "second request response received") } +func HttpStaticPostTest(s *NoTopoSuite) { + // testing url handler app do not support multi-thread + s.SkipIfMultiWorker() + vpp := s.Containers.Vpp.VppInstance + serverAddress := s.VppAddr() + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug max-body-size 1m")) + s.Log(vpp.Vppctl("test-url-handler enable")) + + body := make([]byte, 131072) + _, err := rand.Read(body) + client := NewHttpClient(defaultHttpTimeout) + req, err := http.NewRequest("POST", "http://"+serverAddress+":80/test3", bytes.NewBuffer(body)) + s.AssertNil(err, fmt.Sprint(err)) + resp, err := client.Do(req) + s.AssertNil(err, fmt.Sprint(err)) + defer resp.Body.Close() + s.AssertHttpStatus(resp, 200) + _, err = io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) +} + func HttpCliTest(s *VethsSuite) { s.Containers.ServerVpp.VppInstance.Vppctl("http cli server") diff --git a/src/plugins/http_static/http_static.api b/src/plugins/http_static/http_static.api index bd0cebc45d2..5c1eaf7b9d2 100644 --- a/src/plugins/http_static/http_static.api +++ b/src/plugins/http_static/http_static.api @@ -3,41 +3,7 @@ This file defines static http server control-plane API messages */ -option version = "2.4.0"; - -/** \brief Configure and enable the static http server - @param client_index - opaque cookie to identify the sender - @param context - sender context, to match reply w/ request - @param fifo_size - size (in bytes) of the session FIFOs - @param cache_size_limit - size (in bytes) of the in-memory file data cache - @param max_age - how long a response is considered fresh (in seconds) - @param prealloc_fifos - number of preallocated fifos (usually 0) - @param private_segment_size - fifo segment size (usually 0) - @param www_root - html root path - @param uri - bind URI, defaults to "tcp://0.0.0.0/80" -*/ - -autoreply define http_static_enable_v2 { - option deprecated; - - /* Client identifier, set from api_main.my_client_index */ - u32 client_index; - - /* Arbitrary context, so client can match reply to request */ - u32 context; - /* Typical options */ - u32 fifo_size; - u32 cache_size_limit; - u32 max_age [default=600]; - /* Unusual options */ - u32 prealloc_fifos; - u32 private_segment_size; - - /* Root of the html path */ - string www_root[256]; - /* The bind URI */ - string uri[256]; -}; +option version = "2.5.0"; /** \brief Configure and enable the static http server @param client_index - opaque cookie to identify the sender @@ -45,6 +11,7 @@ autoreply define http_static_enable_v2 { @param fifo_size - size (in bytes) of the session FIFOs @param cache_size_limit - size (in bytes) of the in-memory file data cache @param max_age - how long a response is considered fresh (in seconds) + @param max_body_size - maximum size of a request body (in bytes) @param keepalive_timeout - timeout during which client connection will stay open (in seconds) @param prealloc_fifos - number of preallocated fifos (usually 0) @param private_segment_size - fifo segment size (usually 0) @@ -52,7 +19,7 @@ autoreply define http_static_enable_v2 { @param uri - bind URI, defaults to "tcp://0.0.0.0/80" */ -autoreply define http_static_enable_v3 { +autoreply define http_static_enable_v4 { option deprecated; /* Client identifier, set from api_main.my_client_index */ @@ -65,6 +32,7 @@ autoreply define http_static_enable_v3 { u32 cache_size_limit; u32 max_age [default=600]; u32 keepalive_timeout [default=60]; + u64 max_body_size [default=8000]; /* Unusual options */ u32 prealloc_fifos; u32 private_segment_size; @@ -76,12 +44,14 @@ autoreply define http_static_enable_v3 { }; /** \brief Configure and enable the static http server + @param client_index - opaque cookie to identify the sender @param context - sender context, to match reply w/ request @param fifo_size - size (in bytes) of the session FIFOs @param cache_size_limit - size (in bytes) of the in-memory file data cache @param max_age - how long a response is considered fresh (in seconds) @param max_body_size - maximum size of a request body (in bytes) + @param rx_buff_thresh - maximum size of a large memory allocation (in bytes) @param keepalive_timeout - timeout during which client connection will stay open (in seconds) @param prealloc_fifos - number of preallocated fifos (usually 0) @param private_segment_size - fifo segment size (usually 0) @@ -89,7 +59,7 @@ autoreply define http_static_enable_v3 { @param uri - bind URI, defaults to "tcp://0.0.0.0/80" */ -autoreply define http_static_enable_v4 { +autoreply define http_static_enable_v5 { /* Client identifier, set from api_main.my_client_index */ u32 client_index; @@ -100,7 +70,8 @@ autoreply define http_static_enable_v4 { u32 cache_size_limit; u32 max_age [default=600]; u32 keepalive_timeout [default=60]; - u64 max_body_size [default=8000]; + u64 max_body_size [default=8192]; + u32 rx_buff_thresh [default=1048576]; /* Unusual options */ u32 prealloc_fifos; u32 private_segment_size; diff --git a/src/plugins/http_static/http_static.c b/src/plugins/http_static/http_static.c index 2574f65c223..85b044fb860 100644 --- a/src/plugins/http_static/http_static.c +++ b/src/plugins/http_static/http_static.c @@ -67,7 +67,7 @@ hss_register_url_handler (hss_url_handler_fn fp, const char *url, static int hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, u32 private_segment_size, u8 *www_root, u8 *uri, u32 max_age, - u32 keepalive_timeout, u64 max_body_size) + u32 keepalive_timeout, u64 max_body_size, u32 rx_buff_thresh) { hss_main_t *hsm = &hss_main; int rv; @@ -81,6 +81,7 @@ hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, hsm->default_listener.cache_size = cache_limit; hsm->default_listener.max_age = max_age; hsm->default_listener.max_body_size = max_body_size; + hsm->default_listener.rx_buff_thresh = rx_buff_thresh; hsm->default_listener.keepalive_timeout = keepalive_timeout; hsm->have_default_listener = 1; @@ -109,49 +110,29 @@ hss_enable_api (u32 fifo_size, u32 cache_limit, u32 prealloc_fifos, /* API message handler */ static void -vl_api_http_static_enable_v2_t_handler (vl_api_http_static_enable_v2_t *mp) -{ - vl_api_http_static_enable_v2_reply_t *rmp; - hss_main_t *hsm = &hss_main; - int rv; - - mp->uri[ARRAY_LEN (mp->uri) - 1] = 0; - mp->www_root[ARRAY_LEN (mp->www_root) - 1] = 0; - - rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit), - ntohl (mp->prealloc_fifos), - ntohl (mp->private_segment_size), mp->www_root, mp->uri, - ntohl (mp->max_age), HSS_DEFAULT_KEEPALIVE_TIMEOUT, - HSS_DEFAULT_MAX_BODY_SIZE); - - REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V2_REPLY); -} - -/* API message handler */ -static void -vl_api_http_static_enable_v3_t_handler (vl_api_http_static_enable_v3_t *mp) +vl_api_http_static_enable_v4_t_handler (vl_api_http_static_enable_v4_t *mp) { - vl_api_http_static_enable_v3_reply_t *rmp; + vl_api_http_static_enable_v4_reply_t *rmp; hss_main_t *hsm = &hss_main; int rv; mp->uri[ARRAY_LEN (mp->uri) - 1] = 0; mp->www_root[ARRAY_LEN (mp->www_root) - 1] = 0; - rv = hss_enable_api (ntohl (mp->fifo_size), ntohl (mp->cache_size_limit), - ntohl (mp->prealloc_fifos), - ntohl (mp->private_segment_size), mp->www_root, mp->uri, - ntohl (mp->max_age), ntohl (mp->keepalive_timeout), - HSS_DEFAULT_MAX_BODY_SIZE); + rv = hss_enable_api ( + ntohl (mp->fifo_size), ntohl (mp->cache_size_limit), + ntohl (mp->prealloc_fifos), ntohl (mp->private_segment_size), mp->www_root, + mp->uri, ntohl (mp->max_age), ntohl (mp->keepalive_timeout), + ntohl (mp->max_body_size), HSS_DEFAULT_RX_BUFFER_THRESH); - REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V3_REPLY); + REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V4_REPLY); } /* API message handler */ static void -vl_api_http_static_enable_v4_t_handler (vl_api_http_static_enable_v4_t *mp) +vl_api_http_static_enable_v5_t_handler (vl_api_http_static_enable_v5_t *mp) { - vl_api_http_static_enable_v4_reply_t *rmp; + vl_api_http_static_enable_v5_reply_t *rmp; hss_main_t *hsm = &hss_main; int rv; @@ -162,9 +143,9 @@ vl_api_http_static_enable_v4_t_handler (vl_api_http_static_enable_v4_t *mp) ntohl (mp->prealloc_fifos), ntohl (mp->private_segment_size), mp->www_root, mp->uri, ntohl (mp->max_age), ntohl (mp->keepalive_timeout), - ntohl (mp->max_body_size)); + ntohl (mp->max_body_size), ntohl (mp->rx_buff_thresh)); - REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V4_REPLY); + REPLY_MACRO (VL_API_HTTP_STATIC_ENABLE_V5_REPLY); } #include diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h index 25ee19548d2..678fb6347d8 100644 --- a/src/plugins/http_static/http_static.h +++ b/src/plugins/http_static/http_static.h @@ -25,6 +25,7 @@ #define HSS_DEFAULT_MAX_AGE 600 #define HSS_DEFAULT_MAX_BODY_SIZE 8192 +#define HSS_DEFAULT_RX_BUFFER_THRESH 1 << 20 #define HSS_DEFAULT_KEEPALIVE_TIMEOUT 60 /** @file http_static.h @@ -63,6 +64,10 @@ typedef struct hss_session_ http_headers_ctx_t resp_headers; /** Response header buffer */ u8 *headers_buf; + /** RX buffer (POST body) */ + u8 *rx_buff; + /** Current RX buffer offset */ + u64 rx_buff_offset; /** POST body left to receive */ u64 left_recv; /** threshold for switching to pointers */ @@ -137,6 +142,8 @@ typedef struct hss_listener_ u64 cache_size; /** Maximum size of a request body (in bytes) **/ u64 max_body_size; + /** Maximum size of a large memory allocation */ + u32 rx_buff_thresh; /** Timeout during which client connection will stay open */ u32 keepalive_timeout; /** How long a response is considered fresh (in seconds) */ diff --git a/src/plugins/http_static/http_static_test.c b/src/plugins/http_static/http_static_test.c index 56487893220..aba7bc4ffbf 100644 --- a/src/plugins/http_static/http_static_test.c +++ b/src/plugins/http_static/http_static_test.c @@ -39,100 +39,10 @@ http_static_test_main_t http_static_test_main; #include static int -api_http_static_enable_v2 (vat_main_t *vam) -{ - unformat_input_t *line_input = vam->input; - vl_api_http_static_enable_v2_t *mp; - u64 tmp; - u8 *www_root = 0; - u8 *uri = 0; - u32 prealloc_fifos = 0; - u32 private_segment_size = 0; - u32 fifo_size = 8 << 10; - u32 cache_size_limit = 1 << 20; - u32 max_age = HSS_DEFAULT_MAX_AGE; - int ret; - - /* Parse args required to build the message */ - while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) - { - if (unformat (line_input, "www-root %s", &www_root)) - ; - else if (unformat (line_input, "prealloc-fifos %d", &prealloc_fifos)) - ; - else if (unformat (line_input, "private-segment-size %U", - unformat_memory_size, &tmp)) - { - if (tmp >= 0x100000000ULL) - { - errmsg ("private segment size %llu, too large", tmp); - return -99; - } - private_segment_size = (u32) tmp; - } - else if (unformat (line_input, "fifo-size %U", unformat_memory_size, - &tmp)) - { - if (tmp >= 0x100000000ULL) - { - errmsg ("fifo-size %llu, too large", tmp); - return -99; - } - fifo_size = (u32) tmp; - } - else if (unformat (line_input, "cache-size %U", unformat_memory_size, - &tmp)) - { - if (tmp < (128ULL << 10)) - { - errmsg ("cache-size must be at least 128kb"); - return -99; - } - cache_size_limit = (u32) tmp; - } - else if (unformat (line_input, "max-age %d", &max_age)) - ; - else if (unformat (line_input, "uri %s", &uri)) - ; - else - { - errmsg ("unknown input `%U'", format_unformat_error, line_input); - return -99; - } - } - - if (www_root == 0) - { - errmsg ("Must specify www-root"); - return -99; - } - - if (uri == 0) - uri = format (0, "tcp://0.0.0.0/80%c", 0); - - /* Construct the API message */ - M (HTTP_STATIC_ENABLE_V2, mp); - strncpy_s ((char *) mp->www_root, 256, (const char *) www_root, 256); - strncpy_s ((char *) mp->uri, 256, (const char *) uri, 256); - mp->fifo_size = ntohl (fifo_size); - mp->cache_size_limit = ntohl (cache_size_limit); - mp->prealloc_fifos = ntohl (prealloc_fifos); - mp->private_segment_size = ntohl (private_segment_size); - mp->max_age = ntohl (max_age); - - /* send it... */ - S (mp); - - /* Wait for a reply... */ - W (ret); - return ret; -} - -static int -api_http_static_enable_v3 (vat_main_t *vam) +api_http_static_enable_v4 (vat_main_t *vam) { unformat_input_t *line_input = vam->input; - vl_api_http_static_enable_v3_t *mp; + vl_api_http_static_enable_v4_t *mp; u64 tmp; u8 *www_root = 0; u8 *uri = 0; @@ -142,6 +52,7 @@ api_http_static_enable_v3 (vat_main_t *vam) u32 cache_size_limit = 1 << 20; u32 max_age = HSS_DEFAULT_MAX_AGE; u32 keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT; + u64 max_body_size = HSS_DEFAULT_MAX_BODY_SIZE; int ret; /* Parse args required to build the message */ @@ -188,6 +99,8 @@ api_http_static_enable_v3 (vat_main_t *vam) ; else if (unformat (line_input, "uri %s", &uri)) ; + else if (unformat (line_input, "max-body-size %llu", &max_body_size)) + ; else { errmsg ("unknown input `%U'", format_unformat_error, line_input); @@ -205,7 +118,7 @@ api_http_static_enable_v3 (vat_main_t *vam) uri = format (0, "tcp://0.0.0.0/80%c", 0); /* Construct the API message */ - M (HTTP_STATIC_ENABLE_V3, mp); + M (HTTP_STATIC_ENABLE_V4, mp); strncpy_s ((char *) mp->www_root, 256, (const char *) www_root, 256); strncpy_s ((char *) mp->uri, 256, (const char *) uri, 256); mp->fifo_size = ntohl (fifo_size); @@ -214,6 +127,8 @@ api_http_static_enable_v3 (vat_main_t *vam) mp->private_segment_size = ntohl (private_segment_size); mp->max_age = ntohl (max_age); mp->keepalive_timeout = ntohl (keepalive_timeout); + mp->max_body_size = ntohl (max_body_size); + /* send it... */ S (mp); @@ -223,10 +138,10 @@ api_http_static_enable_v3 (vat_main_t *vam) } static int -api_http_static_enable_v4 (vat_main_t *vam) +api_http_static_enable_v5 (vat_main_t *vam) { unformat_input_t *line_input = vam->input; - vl_api_http_static_enable_v4_t *mp; + vl_api_http_static_enable_v5_t *mp; u64 tmp; u8 *www_root = 0; u8 *uri = 0; @@ -237,6 +152,7 @@ api_http_static_enable_v4 (vat_main_t *vam) u32 max_age = HSS_DEFAULT_MAX_AGE; u32 keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT; u64 max_body_size = HSS_DEFAULT_MAX_BODY_SIZE; + u32 rx_buff_thresh = HSS_DEFAULT_RX_BUFFER_THRESH; int ret; /* Parse args required to build the message */ @@ -283,7 +199,11 @@ api_http_static_enable_v4 (vat_main_t *vam) ; else if (unformat (line_input, "uri %s", &uri)) ; - else if (unformat (line_input, "max-body-size %llu", &max_body_size)) + else if (unformat (line_input, "max-body-size %U", unformat_memory_size, + &max_body_size)) + ; + else if (unformat (line_input, "rx-buff-thresh %U", unformat_memory_size, + &rx_buff_thresh)) ; else { diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index 9914becee58..9c5dfbab5c0 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -21,6 +21,7 @@ #include #include +#include /** @file static_server.c * Static http server, sufficient to serve .html / .css / .js content. @@ -32,7 +33,7 @@ hss_main_t hss_main; static int file_handler_discard_body (hss_session_t *hs, session_t *ts); -static int url_handler_wait_body (hss_session_t *hs, session_t *ts); +static int url_handler_read_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, @@ -66,6 +67,19 @@ hss_add_header (hss_session_t *hs, http_header_name_t name, const char *value, return 0; } +static_always_inline void +hss_confirm_data_read (hss_session_t *hs, u32 n_last_deq) +{ + session_t *ts; + + ts = session_get (hs->vpp_session_index, hs->thread_index); + if (svm_fifo_needs_deq_ntf (ts->rx_fifo, n_last_deq)) + { + svm_fifo_clear_deq_ntf (ts->rx_fifo); + session_program_transport_io_evt (ts->handle, SESSION_IO_EVT_RX); + } +} + static hss_session_t * hss_session_alloc (u32 thread_index) { @@ -121,6 +135,7 @@ hss_session_disconnect_transport (hss_session_t *hs) static void start_send_data (hss_session_t *hs, http_status_code_t status) { + hss_main_t *hsm = &hss_main; http_msg_t msg; session_t *ts; u32 n_enq; @@ -129,6 +144,9 @@ start_send_data (hss_session_t *hs, http_status_code_t status) ts = session_get (hs->vpp_session_index, hs->thread_index); + if (hsm->debug_level > 0) + clib_warning ("status code: %U", format_http_status_code, status); + msg.type = HTTP_MSG_REPLY; msg.code = status; msg.data.body_len = hs->data_len; @@ -291,7 +309,8 @@ try_url_handler (hss_session_t *hs) hss_url_handler_args_t args = {}; uword *p, *url_table; session_t *ts; - u8 *data = 0, *target_path; + u32 max_deq; + u8 *target_path; int rv; target_path = hs->target_path; @@ -313,18 +332,41 @@ try_url_handler (hss_session_t *hs) if (!p) return -1; + hs->rx_buff = 0; + /* Read request body */ if (hs->left_recv) { + hss_listener_t *l = hss_listener_get (hs->listener_index); + if (hs->left_recv > l->rx_buff_thresh) + { + /* TODO: large body (not buffered in memory) */ + clib_warning ("data length %u above threshold %u", hs->left_recv, + l->rx_buff_thresh); + hs->left_recv = 0; + start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR); + hss_session_disconnect_transport (hs); + } + hs->rx_buff_offset = 0; + vec_validate (hs->rx_buff, hs->left_recv - 1); ts = session_get (hs->vpp_session_index, hs->thread_index); - if (svm_fifo_max_dequeue (ts->rx_fifo) < hs->left_recv) + max_deq = svm_fifo_max_dequeue (ts->rx_fifo); + if (max_deq < hs->left_recv) { - hs->read_body_handler = url_handler_wait_body; + hs->read_body_handler = url_handler_read_body; + if (max_deq == 0) + return 0; + rv = svm_fifo_dequeue (ts->rx_fifo, max_deq, hs->rx_buff); + ASSERT (rv == max_deq); + hs->rx_buff_offset = max_deq; + hs->left_recv -= max_deq; + hss_confirm_data_read (hs, max_deq); return 0; } - vec_validate (data, hs->left_recv - 1); - rv = svm_fifo_dequeue (ts->rx_fifo, hs->left_recv, data); + rv = svm_fifo_dequeue (ts->rx_fifo, hs->left_recv, + hs->rx_buff + hs->rx_buff_offset); ASSERT (rv == hs->left_recv); + hss_confirm_data_read (hs, hs->left_recv); hs->left_recv = 0; } @@ -338,13 +380,13 @@ try_url_handler (hss_session_t *hs) args.req_type = hs->rt; args.query = hs->target_query; - args.req_data = data; + args.req_data = hs->rx_buff; 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); + vec_free (hs->rx_buff); /* Wait for data from handler */ if (rv == HSS_URL_HANDLER_ASYNC) @@ -482,9 +524,11 @@ try_file_handler (hss_session_t *hs) svm_fifo_dequeue_drop (ts->rx_fifo, max_dequeue); hs->left_recv -= max_dequeue; hs->read_body_handler = file_handler_discard_body; + hss_confirm_data_read (hs, max_dequeue); return 0; } svm_fifo_dequeue_drop (ts->rx_fifo, hs->left_recv); + hss_confirm_data_read (hs, hs->left_recv); hs->left_recv = 0; } @@ -599,26 +643,29 @@ file_handler_discard_body (hss_session_t *hs, session_t *ts) to_discard = clib_min (max_dequeue, hs->left_recv); svm_fifo_dequeue_drop (ts->rx_fifo, to_discard); hs->left_recv -= to_discard; + hss_confirm_data_read (hs, to_discard); if (hs->left_recv == 0) return try_file_handler (hs); return 0; } static int -url_handler_wait_body (hss_session_t *hs, session_t *ts) +url_handler_read_body (hss_session_t *hs, session_t *ts) { - /* TODO: add support for large content (buffer or stream data) */ - if (svm_fifo_max_dequeue (ts->rx_fifo) < hs->left_recv) - { - clib_warning ("not all data in fifo, max deq %u, left recv %u", - 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; - } - hs->left_recv = 0; - return try_url_handler (hs); + u32 max_dequeue, to_read; + int rv; + + max_dequeue = svm_fifo_max_dequeue (ts->rx_fifo); + to_read = clib_min (max_dequeue, hs->left_recv); + rv = + svm_fifo_dequeue (ts->rx_fifo, to_read, hs->rx_buff + hs->rx_buff_offset); + ASSERT (rv == to_read); + hs->rx_buff_offset += to_read; + hs->left_recv -= to_read; + hss_confirm_data_read (hs, to_read); + if (hs->left_recv == 0) + return try_url_handler (hs); + return 0; } static int @@ -1082,6 +1129,7 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, l->cache_size = 10 << 20; l->max_age = HSS_DEFAULT_MAX_AGE; l->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE; + l->rx_buff_thresh = HSS_DEFAULT_RX_BUFFER_THRESH; l->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT; /* Get a line of input. */ @@ -1119,6 +1167,9 @@ hss_create_command_fn (vlib_main_t *vm, unformat_input_t *input, else if (unformat (line_input, "max-body-size %U", unformat_memory_size, &l->max_body_size)) ; + else if (unformat (line_input, "rx-buff-thresh %U", unformat_memory_size, + &l->rx_buff_thresh)) + ; else if (unformat (line_input, "keepalive-timeout %d", &l->keepalive_timeout)) ; @@ -1214,6 +1265,12 @@ hss_add_del_listener_command_fn (vlib_main_t *vm, unformat_input_t *input, if (!unformat_user (input, unformat_line_input, line_input)) return clib_error_return (0, "No input provided"); + l->cache_size = 10 << 20; + l->max_age = HSS_DEFAULT_MAX_AGE; + l->max_body_size = HSS_DEFAULT_MAX_BODY_SIZE; + l->rx_buff_thresh = HSS_DEFAULT_RX_BUFFER_THRESH; + l->keepalive_timeout = HSS_DEFAULT_KEEPALIVE_TIMEOUT; + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) { if (unformat (line_input, "add")) @@ -1240,6 +1297,9 @@ hss_add_del_listener_command_fn (vlib_main_t *vm, unformat_input_t *input, else if (unformat (line_input, "max-body-size %U", unformat_memory_size, &l->max_body_size)) ; + else if (unformat (line_input, "rx-buff-thresh %U", unformat_memory_size, + &l->rx_buff_thresh)) + ; else { error = clib_error_return (0, "unknown input `%U'", diff --git a/test/asf/test_http_static.py b/test/asf/test_http_static.py index 8d488cb4b22..f6434802918 100644 --- a/test/asf/test_http_static.py +++ b/test/asf/test_http_static.py @@ -64,7 +64,7 @@ class TestHttpStaticVapi(VppAsfTestCase): super(TestHttpStaticVapi, cls).tearDownClass() def test_http_static_vapi(self): - self.vapi.http_static_enable_v3( + self.vapi.http_static_enable_v5( www_root="/tmp", uri="tcp://0.0.0.0/80", ) -- 2.16.6