diff options
Diffstat (limited to 'src/plugins/hs_apps')
-rw-r--r-- | src/plugins/hs_apps/http_tps.c | 154 |
1 files changed, 115 insertions, 39 deletions
diff --git a/src/plugins/hs_apps/http_tps.c b/src/plugins/hs_apps/http_tps.c index 35a5802f476..39046b38d43 100644 --- a/src/plugins/hs_apps/http_tps.c +++ b/src/plugins/hs_apps/http_tps.c @@ -20,6 +20,8 @@ #include <http/http_header_names.h> #include <http/http_content_types.h> +#define HTS_RX_BUF_SIZE (64 << 10) + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -28,6 +30,7 @@ typedef struct u64 data_len; u64 data_offset; u32 vpp_session_index; + u32 to_recv; union { /** threshold after which connection is closed */ @@ -36,6 +39,7 @@ typedef struct u32 close_rate; }; u8 *uri; + u8 *rx_buf; http_header_t *resp_headers; } hts_session_t; @@ -105,6 +109,8 @@ hts_session_free (hts_session_t *hs) if (htm->debug_level > 0) clib_warning ("Freeing session %u", hs->session_index); + vec_free (hs->rx_buf); + if (CLIB_DEBUG) clib_memset (hs, 0xfa, sizeof (*hs)); @@ -227,6 +233,8 @@ hts_start_send_data (hts_session_t *hs, http_status_code_t status) http_msg_t msg; session_t *ts; u8 *headers_buf = 0; + u32 n_segs = 1; + svm_fifo_seg_t seg[2]; int rv; if (vec_len (hs->resp_headers)) @@ -235,6 +243,9 @@ hts_start_send_data (hts_session_t *hs, http_status_code_t status) vec_free (hs->resp_headers); msg.data.headers_offset = 0; msg.data.headers_len = vec_len (headers_buf); + seg[1].data = headers_buf; + seg[1].len = msg.data.headers_len; + n_segs = 2; } else { @@ -248,17 +259,14 @@ hts_start_send_data (hts_session_t *hs, http_status_code_t status) msg.data.body_len = hs->data_len; msg.data.body_offset = msg.data.headers_len; msg.data.len = msg.data.body_len + msg.data.headers_len; + seg[0].data = (u8 *) &msg; + seg[0].len = sizeof (msg); ts = session_get (hs->vpp_session_index, hs->thread_index); - rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg); - ASSERT (rv == sizeof (msg)); - - if (msg.data.headers_len) - { - rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf); - ASSERT (rv == msg.data.headers_len); - vec_free (headers_buf); - } + rv = svm_fifo_enqueue_segments (ts->tx_fifo, seg, n_segs, + 0 /* allow partial */); + vec_free (headers_buf); + ASSERT (rv == (sizeof (msg) + msg.data.headers_len)); if (!msg.data.body_len) { @@ -323,6 +331,40 @@ done: return rc; } +static inline void +hts_session_rx_body (hts_session_t *hs, session_t *ts) +{ + hts_main_t *htm = &hts_main; + u32 n_deq; + int rv; + + n_deq = svm_fifo_max_dequeue (ts->rx_fifo); + if (!htm->no_zc) + { + svm_fifo_dequeue_drop_all (ts->rx_fifo); + } + else + { + n_deq = clib_min (n_deq, HTS_RX_BUF_SIZE); + rv = svm_fifo_dequeue (ts->rx_fifo, n_deq, hs->rx_buf); + ASSERT (rv == n_deq); + } + hs->to_recv -= n_deq; + + if (hs->close_threshold > 0) + { + if ((f64) (hs->data_len - hs->to_recv) / hs->data_len > + hs->close_threshold) + hts_disconnect_transport (hs); + } + + if (hs->to_recv == 0) + { + hts_start_send_data (hs, HTTP_STATUS_OK); + vec_free (hs->rx_buf); + } +} + static int hts_ts_rx_callback (session_t *ts) { @@ -333,44 +375,77 @@ hts_ts_rx_callback (session_t *ts) int rv; hs = hts_session_get (ts->thread_index, ts->opaque); - hs->data_len = 0; - hs->resp_headers = 0; - /* Read the http message header */ - rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg); - ASSERT (rv == sizeof (msg)); - - if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET) + if (hs->to_recv == 0) { - http_add_header (&hs->resp_headers, - http_header_name_token (HTTP_HEADER_ALLOW), - http_token_lit ("GET")); - hts_start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED); - goto done; - } + hs->data_len = 0; + hs->resp_headers = 0; + hs->rx_buf = 0; - if (msg.data.target_path_len == 0 || - msg.data.target_form != HTTP_TARGET_ORIGIN_FORM) - { - hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST); - goto done; - } + /* Read the http message header */ + rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg); + ASSERT (rv == sizeof (msg)); - vec_validate (target, msg.data.target_path_len - 1); - rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset, - msg.data.target_path_len, target); - ASSERT (rv == msg.data.target_path_len); + if (msg.type != HTTP_MSG_REQUEST) + { + hts_start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR); + goto done; + } + if (msg.method_type != HTTP_REQ_GET && msg.method_type != HTTP_REQ_POST) + { + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_ALLOW), + http_token_lit ("GET, POST")); + hts_start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED); + goto done; + } - if (htm->debug_level) - clib_warning ("Request target: %v", target); + if (msg.data.target_path_len == 0 || + msg.data.target_form != HTTP_TARGET_ORIGIN_FORM) + { + hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST); + goto done; + } - if (try_test_file (hs, target)) - hts_start_send_data (hs, HTTP_STATUS_NOT_FOUND); + vec_validate (target, msg.data.target_path_len - 1); + rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset, + msg.data.target_path_len, target); + ASSERT (rv == msg.data.target_path_len); - vec_free (target); + if (htm->debug_level) + clib_warning ("%s request target: %v", + msg.method_type == HTTP_REQ_GET ? "GET" : "POST", + target); + + if (msg.method_type == HTTP_REQ_GET) + { + if (try_test_file (hs, target)) + hts_start_send_data (hs, HTTP_STATUS_NOT_FOUND); + vec_free (target); + } + else + { + vec_free (target); + if (!msg.data.body_len) + { + hts_start_send_data (hs, HTTP_STATUS_BAD_REQUEST); + goto done; + } + /* drop everything up to body */ + svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.body_offset); + hs->to_recv = msg.data.body_len; + if (htm->no_zc) + vec_validate (hs->rx_buf, HTS_RX_BUF_SIZE - 1); + hts_session_rx_body (hs, ts); + return 0; + } + + done: + svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.len); + } + else + hts_session_rx_body (hs, ts); -done: - svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.len); return 0; } @@ -397,6 +472,7 @@ hts_ts_accept_callback (session_t *ts) hs = hts_session_alloc (ts->thread_index); hs->vpp_session_index = ts->session_index; + hs->to_recv = 0; ts->opaque = hs->session_index; ts->session_state = SESSION_STATE_READY; |