From 258b82975b120b3deb34483254f1d40dca5bb79d Mon Sep 17 00:00:00 2001 From: Matus Fabian Date: Tue, 19 Nov 2024 15:03:26 +0100 Subject: [PATCH] http: track requests as independent objects Type: improvement Change-Id: I6c1808a82f61c71f34eab12ae5f99cca5fee8854 Signed-off-by: Matus Fabian --- src/plugins/http/http.c | 323 ++++++++++++++++++++-------------------- src/plugins/http/http.h | 62 +++++--- 2 files changed, 203 insertions(+), 182 deletions(-) diff --git a/src/plugins/http/http.c b/src/plugins/http/http.c index 1ea5a08fbf6..7c0b55e26d2 100644 --- a/src/plugins/http/http.c +++ b/src/plugins/http/http.c @@ -58,10 +58,10 @@ format_http_req_state (u8 *s, va_list *va) do \ { \ HTTP_DBG (1, "changing http req state: %U -> %U", \ - format_http_req_state, (_hc)->req_state, \ + format_http_req_state, (_hc)->req.state, \ format_http_req_state, _state); \ - ASSERT ((_hc)->req_state != HTTP_REQ_STATE_TUNNEL); \ - (_hc)->req_state = _state; \ + ASSERT ((_hc)->req.state != HTTP_REQ_STATE_TUNNEL); \ + (_hc)->req.state = _state; \ } \ while (0) @@ -422,7 +422,7 @@ http_ts_reset_callback (session_t *ts) hc = http_conn_get_w_thread (ts->opaque, ts->thread_index); hc->state = HTTP_CONN_STATE_CLOSED; - http_buffer_free (&hc->tx_buf); + http_buffer_free (&hc->req.tx_buf); http_req_state_change (hc, HTTP_REQ_STATE_WAIT_TRANSPORT_METHOD); session_transport_reset_notify (&hc->connection); @@ -515,8 +515,8 @@ http_read_message (http_conn_t *hc) if (PREDICT_FALSE (max_deq == 0)) return -1; - vec_validate (hc->rx_buf, max_deq - 1); - n_read = svm_fifo_peek (ts->rx_fifo, 0, max_deq, hc->rx_buf); + vec_validate (hc->req.rx_buf, max_deq - 1); + n_read = svm_fifo_peek (ts->rx_fifo, 0, max_deq, hc->req.rx_buf); ASSERT (n_read == max_deq); HTTP_DBG (1, "read %u bytes from rx_fifo", n_read); @@ -530,7 +530,7 @@ http_read_message_drop (http_conn_t *hc, u32 len) ts = session_get_from_handle (hc->h_tc_session_handle); svm_fifo_dequeue_drop (ts->rx_fifo, len); - vec_reset_length (hc->rx_buf); + vec_reset_length (hc->req.rx_buf); if (svm_fifo_is_empty (ts->rx_fifo)) svm_fifo_unset_event (ts->rx_fifo); @@ -543,7 +543,7 @@ http_read_message_drop_all (http_conn_t *hc) ts = session_get_from_handle (hc->h_tc_session_handle); svm_fifo_dequeue_drop_all (ts->rx_fifo); - vec_reset_length (hc->rx_buf); + vec_reset_length (hc->req.rx_buf); if (svm_fifo_is_empty (ts->rx_fifo)) svm_fifo_unset_event (ts->rx_fifo); @@ -589,64 +589,66 @@ v_find_index (u8 *vec, u32 offset, u32 num, char *str) } static void -http_identify_optional_query (http_conn_t *hc) +http_identify_optional_query (http_req_t *req) { int i; - for (i = hc->target_path_offset; - i < (hc->target_path_offset + hc->target_path_len); i++) + for (i = req->target_path_offset; + i < (req->target_path_offset + req->target_path_len); i++) { - if (hc->rx_buf[i] == '?') + if (req->rx_buf[i] == '?') { - hc->target_query_offset = i + 1; - hc->target_query_len = hc->target_path_offset + hc->target_path_len - - hc->target_query_offset; - hc->target_path_len = hc->target_path_len - hc->target_query_len - 1; + req->target_query_offset = i + 1; + req->target_query_len = req->target_path_offset + + req->target_path_len - + req->target_query_offset; + req->target_path_len = + req->target_path_len - req->target_query_len - 1; break; } } } static int -http_get_target_form (http_conn_t *hc) +http_get_target_form (http_req_t *req) { int i; /* "*" */ - if ((hc->rx_buf[hc->target_path_offset] == '*') && - (hc->target_path_len == 1)) + if ((req->rx_buf[req->target_path_offset] == '*') && + (req->target_path_len == 1)) { - hc->target_form = HTTP_TARGET_ASTERISK_FORM; + req->target_form = HTTP_TARGET_ASTERISK_FORM; return 0; } /* 1*( "/" segment ) [ "?" query ] */ - if (hc->rx_buf[hc->target_path_offset] == '/') + if (req->rx_buf[req->target_path_offset] == '/') { /* drop leading slash */ - hc->target_path_len--; - hc->target_path_offset++; - hc->target_form = HTTP_TARGET_ORIGIN_FORM; - http_identify_optional_query (hc); + req->target_path_len--; + req->target_path_offset++; + req->target_form = HTTP_TARGET_ORIGIN_FORM; + http_identify_optional_query (req); return 0; } /* scheme "://" host [ ":" port ] *( "/" segment ) [ "?" query ] */ - i = v_find_index (hc->rx_buf, hc->target_path_offset, hc->target_path_len, + i = v_find_index (req->rx_buf, req->target_path_offset, req->target_path_len, "://"); if (i > 0) { - hc->target_form = HTTP_TARGET_ABSOLUTE_FORM; - http_identify_optional_query (hc); + req->target_form = HTTP_TARGET_ABSOLUTE_FORM; + http_identify_optional_query (req); return 0; } /* host ":" port */ - for (i = hc->target_path_offset; - i < (hc->target_path_offset + hc->target_path_len); i++) + for (i = req->target_path_offset; + i < (req->target_path_offset + req->target_path_len); i++) { - if ((hc->rx_buf[i] == ':') && (isdigit (hc->rx_buf[i + 1]))) + if ((req->rx_buf[i] == ':') && (isdigit (req->rx_buf[i + 1]))) { - hc->target_form = HTTP_TARGET_AUTHORITY_FORM; + req->target_form = HTTP_TARGET_AUTHORITY_FORM; return 0; } } @@ -655,13 +657,13 @@ http_get_target_form (http_conn_t *hc) } static int -http_parse_request_line (http_conn_t *hc, http_status_code_t *ec) +http_parse_request_line (http_req_t *req, http_status_code_t *ec) { int i, target_len; u32 next_line_offset, method_offset; /* request-line = method SP request-target SP HTTP-version CRLF */ - i = v_find_index (hc->rx_buf, 8, 0, "\r\n"); + i = v_find_index (req->rx_buf, 8, 0, "\r\n"); if (i < 0) { clib_warning ("request line incomplete"); @@ -669,11 +671,11 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec) return -1; } HTTP_DBG (2, "request line length: %d", i); - hc->control_data_len = i + 2; - next_line_offset = hc->control_data_len; + req->control_data_len = i + 2; + next_line_offset = req->control_data_len; /* there should be at least one more CRLF */ - if (vec_len (hc->rx_buf) < (next_line_offset + 2)) + if (vec_len (req->rx_buf) < (next_line_offset + 2)) { clib_warning ("malformed message, too short"); *ec = HTTP_STATUS_BAD_REQUEST; @@ -686,45 +688,45 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec) * parse a request-line SHOULD ignore at least one empty line (CRLF) * received prior to the request-line. */ - method_offset = hc->rx_buf[0] == '\r' && hc->rx_buf[1] == '\n' ? 2 : 0; + method_offset = req->rx_buf[0] == '\r' && req->rx_buf[1] == '\n' ? 2 : 0; /* parse method */ - if (!memcmp (hc->rx_buf + method_offset, "GET ", 4)) + if (!memcmp (req->rx_buf + method_offset, "GET ", 4)) { HTTP_DBG (0, "GET method"); - hc->method = HTTP_REQ_GET; - hc->target_path_offset = method_offset + 4; + req->method = HTTP_REQ_GET; + req->target_path_offset = method_offset + 4; } - else if (!memcmp (hc->rx_buf + method_offset, "POST ", 5)) + else if (!memcmp (req->rx_buf + method_offset, "POST ", 5)) { HTTP_DBG (0, "POST method"); - hc->method = HTTP_REQ_POST; - hc->target_path_offset = method_offset + 5; + req->method = HTTP_REQ_POST; + req->target_path_offset = method_offset + 5; } - else if (!memcmp (hc->rx_buf + method_offset, "CONNECT ", 8)) + else if (!memcmp (req->rx_buf + method_offset, "CONNECT ", 8)) { HTTP_DBG (0, "CONNECT method"); - hc->method = HTTP_REQ_CONNECT; - hc->target_path_offset = method_offset + 8; - hc->is_tunnel = 1; + req->method = HTTP_REQ_CONNECT; + req->target_path_offset = method_offset + 8; + req->is_tunnel = 1; } else { - if (hc->rx_buf[method_offset] - 'A' <= 'Z' - 'A') + if (req->rx_buf[method_offset] - 'A' <= 'Z' - 'A') { - clib_warning ("method not implemented: %8v", hc->rx_buf); + clib_warning ("method not implemented: %8v", req->rx_buf); *ec = HTTP_STATUS_NOT_IMPLEMENTED; return -1; } else { - clib_warning ("not method name: %8v", hc->rx_buf); + clib_warning ("not method name: %8v", req->rx_buf); *ec = HTTP_STATUS_BAD_REQUEST; return -1; } } /* find version */ - i = v_find_index (hc->rx_buf, next_line_offset - 11, 11, " HTTP/"); + i = v_find_index (req->rx_buf, next_line_offset - 11, 11, " HTTP/"); if (i < 0) { clib_warning ("HTTP version not present"); @@ -732,26 +734,27 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec) return -1; } /* verify major version */ - if (isdigit (hc->rx_buf[i + 6])) + if (isdigit (req->rx_buf[i + 6])) { - if (hc->rx_buf[i + 6] != '1') + if (req->rx_buf[i + 6] != '1') { clib_warning ("HTTP major version '%c' not supported", - hc->rx_buf[i + 6]); + req->rx_buf[i + 6]); *ec = HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED; return -1; } } else { - clib_warning ("HTTP major version '%c' is not digit", hc->rx_buf[i + 6]); + clib_warning ("HTTP major version '%c' is not digit", + req->rx_buf[i + 6]); *ec = HTTP_STATUS_BAD_REQUEST; return -1; } /* parse request-target */ HTTP_DBG (2, "http at %d", i); - target_len = i - hc->target_path_offset; + target_len = i - req->target_path_offset; HTTP_DBG (2, "target_len %d", target_len); if (target_len < 1) { @@ -759,22 +762,22 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec) *ec = HTTP_STATUS_BAD_REQUEST; return -1; } - hc->target_path_len = target_len; - hc->target_query_offset = 0; - hc->target_query_len = 0; - if (http_get_target_form (hc)) + req->target_path_len = target_len; + req->target_query_offset = 0; + req->target_query_len = 0; + if (http_get_target_form (req)) { clib_warning ("invalid target"); *ec = HTTP_STATUS_BAD_REQUEST; return -1; } - HTTP_DBG (2, "request-target path length: %u", hc->target_path_len); - HTTP_DBG (2, "request-target path offset: %u", hc->target_path_offset); - HTTP_DBG (2, "request-target query length: %u", hc->target_query_len); - HTTP_DBG (2, "request-target query offset: %u", hc->target_query_offset); + HTTP_DBG (2, "request-target path length: %u", req->target_path_len); + HTTP_DBG (2, "request-target path offset: %u", req->target_path_offset); + HTTP_DBG (2, "request-target query length: %u", req->target_query_len); + HTTP_DBG (2, "request-target query offset: %u", req->target_query_offset); /* set buffer offset to nex line start */ - hc->rx_buf_offset = next_line_offset; + req->rx_buf_offset = next_line_offset; return 0; } @@ -799,14 +802,15 @@ http_parse_request_line (http_conn_t *hc, http_status_code_t *ec) while (0) static int -http_parse_status_line (http_conn_t *hc) +http_parse_status_line (http_req_t *req) { int i; u32 next_line_offset; u8 *p, *end; u16 status_code = 0; + http_main_t *hm = &http_main; - i = v_find_index (hc->rx_buf, 0, 0, "\r\n"); + i = v_find_index (req->rx_buf, 0, 0, "\r\n"); /* status-line = HTTP-version SP status-code SP [ reason-phrase ] CRLF */ if (i < 0) { @@ -819,13 +823,13 @@ http_parse_status_line (http_conn_t *hc) clib_warning ("status line too short (%d)", i); return -1; } - hc->control_data_len = i + 2; - next_line_offset = hc->control_data_len; - p = hc->rx_buf; - end = hc->rx_buf + i; + req->control_data_len = i + 2; + next_line_offset = req->control_data_len; + p = req->rx_buf; + end = req->rx_buf + i; /* there should be at least one more CRLF */ - if (vec_len (hc->rx_buf) < (next_line_offset + 2)) + if (vec_len (req->rx_buf) < (next_line_offset + 2)) { clib_warning ("malformed message, too short"); return -1; @@ -876,63 +880,63 @@ http_parse_status_line (http_conn_t *hc) clib_warning ("invalid status code %d", status_code); return -1; } - hc->status_code = status_code; - HTTP_DBG (0, "status code: %d", hc->status_code); + req->status_code = hm->sc_by_u16[status_code]; + HTTP_DBG (0, "status code: %d", status_code); /* set buffer offset to nex line start */ - hc->rx_buf_offset = next_line_offset; + req->rx_buf_offset = next_line_offset; return 0; } static int -http_identify_headers (http_conn_t *hc, http_status_code_t *ec) +http_identify_headers (http_req_t *req, http_status_code_t *ec) { int i; /* check if we have any header */ - if ((hc->rx_buf[hc->rx_buf_offset] == '\r') && - (hc->rx_buf[hc->rx_buf_offset + 1] == '\n')) + if ((req->rx_buf[req->rx_buf_offset] == '\r') && + (req->rx_buf[req->rx_buf_offset + 1] == '\n')) { /* just another CRLF -> no headers */ HTTP_DBG (2, "no headers"); - hc->headers_len = 0; - hc->control_data_len += 2; + req->headers_len = 0; + req->control_data_len += 2; return 0; } /* find empty line indicating end of header section */ - i = v_find_index (hc->rx_buf, hc->rx_buf_offset, 0, "\r\n\r\n"); + i = v_find_index (req->rx_buf, req->rx_buf_offset, 0, "\r\n\r\n"); if (i < 0) { clib_warning ("cannot find header section end"); *ec = HTTP_STATUS_BAD_REQUEST; return -1; } - hc->headers_offset = hc->rx_buf_offset; - hc->headers_len = i - hc->rx_buf_offset + 2; - hc->control_data_len += (hc->headers_len + 2); - HTTP_DBG (2, "headers length: %u", hc->headers_len); - HTTP_DBG (2, "headers offset: %u", hc->headers_offset); + req->headers_offset = req->rx_buf_offset; + req->headers_len = i - req->rx_buf_offset + 2; + req->control_data_len += (req->headers_len + 2); + HTTP_DBG (2, "headers length: %u", req->headers_len); + HTTP_DBG (2, "headers offset: %u", req->headers_offset); return 0; } static int -http_identify_message_body (http_conn_t *hc, http_status_code_t *ec) +http_identify_message_body (http_req_t *req, http_status_code_t *ec) { int i, value_len; u8 *end, *p, *value_start; u64 body_len = 0, digit; - hc->body_len = 0; + req->body_len = 0; - if (hc->headers_len == 0) + if (req->headers_len == 0) { HTTP_DBG (2, "no header, no message-body"); return 0; } - if (hc->is_tunnel) + if (req->is_tunnel) { HTTP_DBG (2, "tunnel, no message-body"); return 0; @@ -941,23 +945,23 @@ http_identify_message_body (http_conn_t *hc, http_status_code_t *ec) /* TODO check for chunked transfer coding */ /* try to find Content-Length header */ - i = v_find_index (hc->rx_buf, hc->headers_offset, hc->headers_len, + i = v_find_index (req->rx_buf, req->headers_offset, req->headers_len, "Content-Length:"); if (i < 0) { HTTP_DBG (2, "Content-Length header not present, no message-body"); return 0; } - hc->rx_buf_offset = i + 15; + req->rx_buf_offset = i + 15; - i = v_find_index (hc->rx_buf, hc->rx_buf_offset, hc->headers_len, "\r\n"); + i = v_find_index (req->rx_buf, req->rx_buf_offset, req->headers_len, "\r\n"); if (i < 0) { clib_warning ("end of line missing"); *ec = HTTP_STATUS_BAD_REQUEST; return -1; } - value_len = i - hc->rx_buf_offset; + value_len = i - req->rx_buf_offset; if (value_len < 1) { clib_warning ("invalid header, content length value missing"); @@ -965,8 +969,8 @@ http_identify_message_body (http_conn_t *hc, http_status_code_t *ec) return -1; } - end = hc->rx_buf + hc->rx_buf_offset + value_len; - p = hc->rx_buf + hc->rx_buf_offset; + end = req->rx_buf + req->rx_buf_offset + value_len; + p = req->rx_buf + req->rx_buf_offset; /* skip leading whitespace */ while (1) { @@ -1022,11 +1026,11 @@ http_identify_message_body (http_conn_t *hc, http_status_code_t *ec) p++; } - hc->body_len = body_len; + req->body_len = body_len; - hc->body_offset = hc->headers_offset + hc->headers_len + 2; - HTTP_DBG (2, "body length: %llu", hc->body_len); - HTTP_DBG (2, "body offset: %u", hc->body_offset); + req->body_offset = req->headers_offset + req->headers_len + 2; + HTTP_DBG (2, "body length: %llu", req->body_len); + HTTP_DBG (2, "body offset: %u", req->body_offset); return 0; } @@ -1041,7 +1045,6 @@ http_req_state_wait_transport_reply (http_conn_t *hc, session_t *as; u32 len, max_enq, body_sent; http_status_code_t ec; - http_main_t *hm = &http_main; rv = http_read_message (hc); @@ -1052,23 +1055,23 @@ http_req_state_wait_transport_reply (http_conn_t *hc, return HTTP_SM_STOP; } - HTTP_DBG (3, "%v", hc->rx_buf); + HTTP_DBG (3, "%v", hc->req.rx_buf); - if (vec_len (hc->rx_buf) < 8) + if (vec_len (hc->req.rx_buf) < 8) { clib_warning ("response buffer too short"); goto error; } - rv = http_parse_status_line (hc); + rv = http_parse_status_line (&hc->req); if (rv) goto error; - rv = http_identify_headers (hc, &ec); + rv = http_identify_headers (&hc->req, &ec); if (rv) goto error; - rv = http_identify_message_body (hc, &ec); + rv = http_identify_message_body (&hc->req, &ec); if (rv) goto error; @@ -1077,33 +1080,33 @@ http_req_state_wait_transport_reply (http_conn_t *hc, as = session_get_from_handle (hc->h_pa_session_handle); max_enq = svm_fifo_max_enqueue (as->rx_fifo); max_enq -= sizeof (msg); - if (max_enq < hc->control_data_len) + if (max_enq < hc->req.control_data_len) { clib_warning ("not enough room for control data in app's rx fifo"); goto error; } - len = clib_min (max_enq, vec_len (hc->rx_buf)); + len = clib_min (max_enq, vec_len (hc->req.rx_buf)); msg.type = HTTP_MSG_REPLY; - msg.code = hm->sc_by_u16[hc->status_code]; - msg.data.headers_offset = hc->headers_offset; - msg.data.headers_len = hc->headers_len; - msg.data.body_offset = hc->body_offset; - msg.data.body_len = hc->body_len; + msg.code = hc->req.status_code; + msg.data.headers_offset = hc->req.headers_offset; + msg.data.headers_len = hc->req.headers_len; + msg.data.body_offset = hc->req.body_offset; + msg.data.body_len = hc->req.body_len; msg.data.type = HTTP_MSG_DATA_INLINE; msg.data.len = len; svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) }, - { hc->rx_buf, len } }; + { hc->req.rx_buf, len } }; rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2, 0 /* allow partial */); ASSERT (rv == (sizeof (msg) + len)); http_read_message_drop (hc, len); - body_sent = len - hc->control_data_len; - hc->to_recv = hc->body_len - body_sent; - if (hc->to_recv == 0) + body_sent = len - hc->req.control_data_len; + hc->req.to_recv = hc->req.body_len - body_sent; + if (hc->req.to_recv == 0) { /* all sent, we are done */ http_req_state_change (hc, HTTP_REQ_STATE_WAIT_APP_METHOD); @@ -1145,23 +1148,23 @@ http_req_state_wait_transport_method (http_conn_t *hc, if (rv) return HTTP_SM_STOP; - HTTP_DBG (3, "%v", hc->rx_buf); + HTTP_DBG (3, "%v", hc->req.rx_buf); - if (vec_len (hc->rx_buf) < 8) + if (vec_len (hc->req.rx_buf) < 8) { ec = HTTP_STATUS_BAD_REQUEST; goto error; } - rv = http_parse_request_line (hc, &ec); + rv = http_parse_request_line (&hc->req, &ec); if (rv) goto error; - rv = http_identify_headers (hc, &ec); + rv = http_identify_headers (&hc->req, &ec); if (rv) goto error; - rv = http_identify_message_body (hc, &ec); + rv = http_identify_message_body (&hc->req, &ec); if (rv) goto error; @@ -1169,40 +1172,40 @@ http_req_state_wait_transport_method (http_conn_t *hc, * if there is some space send also portion of body */ as = session_get_from_handle (hc->h_pa_session_handle); max_enq = svm_fifo_max_enqueue (as->rx_fifo); - if (max_enq < hc->control_data_len) + if (max_enq < hc->req.control_data_len) { clib_warning ("not enough room for control data in app's rx fifo"); ec = HTTP_STATUS_INTERNAL_ERROR; goto error; } /* do not dequeue more than one HTTP request, we do not support pipelining */ - max_deq = - clib_min (hc->control_data_len + hc->body_len, vec_len (hc->rx_buf)); + max_deq = clib_min (hc->req.control_data_len + hc->req.body_len, + vec_len (hc->req.rx_buf)); len = clib_min (max_enq, max_deq); msg.type = HTTP_MSG_REQUEST; - msg.method_type = hc->method; + msg.method_type = hc->req.method; msg.data.type = HTTP_MSG_DATA_INLINE; msg.data.len = len; - msg.data.target_form = hc->target_form; - msg.data.target_path_offset = hc->target_path_offset; - msg.data.target_path_len = hc->target_path_len; - msg.data.target_query_offset = hc->target_query_offset; - msg.data.target_query_len = hc->target_query_len; - msg.data.headers_offset = hc->headers_offset; - msg.data.headers_len = hc->headers_len; - msg.data.body_offset = hc->body_offset; - msg.data.body_len = hc->body_len; + msg.data.target_form = hc->req.target_form; + msg.data.target_path_offset = hc->req.target_path_offset; + msg.data.target_path_len = hc->req.target_path_len; + msg.data.target_query_offset = hc->req.target_query_offset; + msg.data.target_query_len = hc->req.target_query_len; + msg.data.headers_offset = hc->req.headers_offset; + msg.data.headers_len = hc->req.headers_len; + msg.data.body_offset = hc->req.body_offset; + msg.data.body_len = hc->req.body_len; svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) }, - { hc->rx_buf, len } }; + { hc->req.rx_buf, len } }; rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2, 0 /* allow partial */); ASSERT (rv == (sizeof (msg) + len)); - body_sent = len - hc->control_data_len; - hc->to_recv = hc->body_len - body_sent; - if (hc->to_recv == 0) + body_sent = len - hc->req.control_data_len; + hc->req.to_recv = hc->req.body_len - body_sent; + if (hc->req.to_recv == 0) { /* drop everything, we do not support pipelining */ http_read_message_drop_all (hc); @@ -1285,14 +1288,14 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) /* RFC9110 9.3.6: A server MUST NOT send Content-Length header field in a * 2xx (Successful) response to CONNECT. */ - if (hc->is_tunnel && http_status_code_str[msg.code][0] == '2') + if (hc->req.is_tunnel && http_status_code_str[msg.code][0] == '2') { ASSERT (msg.data.body_len == 0); next_state = HTTP_REQ_STATE_TUNNEL; /* cleanup some stuff we don't need anymore in tunnel mode */ http_conn_timer_stop (hc); - vec_free (hc->rx_buf); - http_buffer_free (&hc->tx_buf); + vec_free (hc->req.rx_buf); + http_buffer_free (&hc->req.tx_buf); } else response = format (response, content_len_template, msg.data.body_len); @@ -1338,7 +1341,7 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp) if (msg.data.body_len) { /* Start sending the actual data */ - http_buffer_init (&hc->tx_buf, msg_to_buf_type[msg.data.type], + http_buffer_init (&hc->req.tx_buf, msg_to_buf_type[msg.data.type], as->tx_fifo, msg.data.body_len); next_state = HTTP_REQ_STATE_APP_IO_MORE_DATA; sm_result = HTTP_SM_CONTINUE; @@ -1459,7 +1462,7 @@ http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp) /* Any headers from app? */ msg.data.headers_len ? "" : "\r\n"); - http_buffer_init (&hc->tx_buf, msg_to_buf_type[msg.data.type], + http_buffer_init (&hc->req.tx_buf, msg_to_buf_type[msg.data.type], as->tx_fifo, msg.data.body_len); next_state = HTTP_REQ_STATE_APP_IO_MORE_DATA; @@ -1561,7 +1564,7 @@ http_req_state_transport_io_more_data (http_conn_t *hc, } svm_fifo_dequeue_drop (ts->rx_fifo, rv); - if (rv > hc->to_recv) + if (rv > hc->req.to_recv) { clib_warning ("http protocol error: received more data than expected"); session_transport_closing_notify (&hc->connection); @@ -1569,13 +1572,13 @@ http_req_state_transport_io_more_data (http_conn_t *hc, http_req_state_change (hc, HTTP_REQ_STATE_WAIT_APP_METHOD); return HTTP_SM_ERROR; } - hc->to_recv -= rv; - HTTP_DBG (1, "drained %d from ts; remains %lu", rv, hc->to_recv); + hc->req.to_recv -= rv; + HTTP_DBG (1, "drained %d from ts; remains %lu", rv, hc->req.to_recv); /* Finished transaction: * server back to HTTP_REQ_STATE_WAIT_APP_REPLY * client to HTTP_REQ_STATE_WAIT_APP_METHOD */ - if (hc->to_recv == 0) + if (hc->req.to_recv == 0) http_req_state_change (hc, hc->is_server ? HTTP_REQ_STATE_WAIT_APP_REPLY : HTTP_REQ_STATE_WAIT_APP_METHOD); @@ -1593,7 +1596,7 @@ static http_sm_result_t http_req_state_app_io_more_data (http_conn_t *hc, transport_send_params_t *sp) { u32 max_send = 64 << 10, n_segs; - http_buffer_t *hb = &hc->tx_buf; + http_buffer_t *hb = &hc->req.tx_buf; svm_fifo_seg_t *seg; session_t *ts; int sent = 0; @@ -1637,7 +1640,7 @@ http_req_state_app_io_more_data (http_conn_t *hc, transport_send_params_t *sp) http_req_state_change (hc, hc->is_server ? HTTP_REQ_STATE_WAIT_TRANSPORT_METHOD : HTTP_REQ_STATE_WAIT_TRANSPORT_REPLY); - http_buffer_free (&hc->tx_buf); + http_buffer_free (hb); } return HTTP_SM_STOP; @@ -1751,7 +1754,7 @@ static http_sm_handler tx_state_funcs[HTTP_REQ_N_STATES] = { static_always_inline int http_req_state_is_tx_valid (http_conn_t *hc) { - return tx_state_funcs[hc->req_state] ? 1 : 0; + return tx_state_funcs[hc->req.state] ? 1 : 0; } static http_sm_handler rx_state_funcs[HTTP_REQ_N_STATES] = { @@ -1768,7 +1771,7 @@ static http_sm_handler rx_state_funcs[HTTP_REQ_N_STATES] = { static_always_inline int http_req_state_is_rx_valid (http_conn_t *hc) { - return rx_state_funcs[hc->req_state] ? 1 : 0; + return rx_state_funcs[hc->req.state] ? 1 : 0; } static_always_inline void @@ -1780,9 +1783,9 @@ http_req_run_state_machine (http_conn_t *hc, transport_send_params_t *sp, do { if (is_tx) - res = tx_state_funcs[hc->req_state](hc, sp); + res = tx_state_funcs[hc->req.state](hc, sp); else - res = rx_state_funcs[hc->req_state](hc, sp); + res = rx_state_funcs[hc->req.state](hc, sp); if (res == HTTP_SM_ERROR) { HTTP_DBG (1, "error in state machine %d", res); @@ -1816,7 +1819,7 @@ http_ts_rx_callback (session_t *ts) clib_warning ("hc [%u]%x invalid rx state: http req state " "'%U', session state '%U'", ts->thread_index, ts->opaque, format_http_req_state, - hc->req_state, format_http_conn_state, hc); + hc->req.state, format_http_conn_state, hc); svm_fifo_dequeue_drop_all (ts->rx_fifo); return 0; } @@ -1856,9 +1859,9 @@ http_ts_cleanup_callback (session_t *ts, session_cleanup_ntf_t ntf) HTTP_DBG (1, "going to free hc [%u]%x", ts->thread_index, ts->opaque); - vec_free (hc->rx_buf); + vec_free (hc->req.rx_buf); - http_buffer_free (&hc->tx_buf); + http_buffer_free (&hc->req.tx_buf); if (hc->pending_timer == 0) http_conn_timer_stop (hc); @@ -2184,7 +2187,7 @@ http_app_tx_callback (void *session, transport_send_params_t *sp) clib_warning ("hc [%u]%x invalid tx state: http req state " "'%U', session state '%U'", as->thread_index, as->connection_index, - format_http_req_state, hc->req_state, + format_http_req_state, hc->req.state, format_http_conn_state, hc); svm_fifo_dequeue_drop_all (as->tx_fifo); return 0; @@ -2210,7 +2213,7 @@ http_app_rx_evt_cb (transport_connection_t *tc) http_conn_t *hc = (http_conn_t *) tc; HTTP_DBG (1, "hc [%u]%x", vlib_get_thread_index (), hc->h_hc_index); - if (hc->req_state == HTTP_REQ_STATE_TUNNEL) + if (hc->req.state == HTTP_REQ_STATE_TUNNEL) http_req_state_tunnel_rx (hc, 0); return 0; diff --git a/src/plugins/http/http.h b/src/plugins/http/http.h index 19488fb7ff4..844235cbdbb 100644 --- a/src/plugins/http/http.h +++ b/src/plugins/http/http.h @@ -385,6 +385,45 @@ typedef struct http_msg_ http_msg_data_t data; } http_msg_t; +typedef struct http_req_ +{ + http_req_state_t state; /* state-machine state */ + + http_buffer_t tx_buf; /* message body from app to be sent */ + + /* + * for parsing of incoming message from transport + */ + u8 *rx_buf; /* this should hold at least control data */ + u32 rx_buf_offset; /* current offset during parsing */ + u32 control_data_len; /* start line + headers + empty line */ + + u64 to_recv; /* remaining bytes of message body to receive from transport */ + + u8 is_tunnel; + + /* + * parsed metadata for app + */ + union + { + http_status_code_t status_code; + http_req_method_t method; + }; + + http_target_form_t target_form; + u32 target_path_offset; + u32 target_path_len; + u32 target_query_offset; + u32 target_query_len; + + u32 headers_offset; + u32 headers_len; + + u32 body_offset; + u64 body_len; +} http_req_t; + typedef struct http_tc_ { union @@ -406,28 +445,7 @@ typedef struct http_tc_ u8 *host; u8 is_server; - /* - * Current request - */ - http_req_state_t req_state; - http_req_method_t method; - u8 *rx_buf; - u32 rx_buf_offset; - http_buffer_t tx_buf; - u64 to_recv; - u32 bytes_dequeued; - u32 control_data_len; /* start line + headers + empty line */ - http_target_form_t target_form; - u32 target_path_offset; - u32 target_path_len; - u32 target_query_offset; - u32 target_query_len; - u32 headers_offset; - u32 headers_len; - u32 body_offset; - u64 body_len; - u16 status_code; - u8 is_tunnel; + http_req_t req; } http_conn_t; typedef struct http_worker_