aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/http/http1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/http/http1.c')
-rw-r--r--src/plugins/http/http1.c279
1 files changed, 242 insertions, 37 deletions
diff --git a/src/plugins/http/http1.c b/src/plugins/http/http1.c
index c152956e43c..ec118aa4e52 100644
--- a/src/plugins/http/http1.c
+++ b/src/plugins/http/http1.c
@@ -10,6 +10,13 @@
#include <http/http_status_codes.h>
#include <http/http_timer.h>
+typedef struct http1_main_
+{
+ http_req_t **req_pool;
+} http1_main_t;
+
+static http1_main_t http1_main;
+
const char *http1_upgrade_proto_str[] = { "",
#define _(sym, str) str,
foreach_http_upgrade_proto
@@ -48,6 +55,76 @@ static const char *post_request_template = "POST %s HTTP/1.1\r\n"
"User-Agent: %v\r\n"
"Content-Length: %llu\r\n";
+always_inline http_req_t *
+http1_conn_alloc_req (http_conn_t *hc)
+{
+ http1_main_t *h1m = &http1_main;
+ http_req_t *req;
+ u32 req_index;
+ http_req_handle_t hr_handle;
+
+ pool_get_aligned_safe (h1m->req_pool[hc->c_thread_index], req,
+ CLIB_CACHE_LINE_BYTES);
+ clib_memset (req, 0, sizeof (*req));
+ req->hr_pa_session_handle = SESSION_INVALID_HANDLE;
+ req_index = req - h1m->req_pool[hc->c_thread_index];
+ hr_handle.version = HTTP_VERSION_1;
+ hr_handle.req_index = req_index;
+ req->hr_req_handle = hr_handle.as_u32;
+ req->hr_hc_index = hc->hc_hc_index;
+ req->c_thread_index = hc->c_thread_index;
+ req->c_flags |= TRANSPORT_CONNECTION_F_NO_LOOKUP;
+ hc->opaque = uword_to_pointer (req_index, void *);
+ hc->flags |= HTTP_CONN_F_HAS_REQUEST;
+ return req;
+}
+
+always_inline http_req_t *
+http1_req_get (u32 req_index, u32 thread_index)
+{
+ http1_main_t *h1m = &http1_main;
+
+ return pool_elt_at_index (h1m->req_pool[thread_index], req_index);
+}
+
+always_inline http_req_t *
+http1_req_get_if_valid (u32 req_index, u32 thread_index)
+{
+ http1_main_t *h1m = &http1_main;
+
+ if (pool_is_free_index (h1m->req_pool[thread_index], req_index))
+ return 0;
+ return pool_elt_at_index (h1m->req_pool[thread_index], req_index);
+}
+
+always_inline http_req_t *
+http1_conn_get_req (http_conn_t *hc)
+{
+ http1_main_t *h1m = &http1_main;
+ u32 req_index;
+
+ req_index = pointer_to_uword (hc->opaque);
+ return pool_elt_at_index (h1m->req_pool[hc->c_thread_index], req_index);
+}
+
+always_inline void
+http1_conn_free_req (http_conn_t *hc)
+{
+ http1_main_t *h1m = &http1_main;
+ http_req_t *req;
+ u32 req_index;
+
+ req_index = pointer_to_uword (hc->opaque);
+ req = pool_elt_at_index (h1m->req_pool[hc->c_thread_index], req_index);
+ vec_free (req->headers);
+ vec_free (req->target);
+ http_buffer_free (&req->tx_buf);
+ if (CLIB_DEBUG)
+ memset (req, 0xba, sizeof (*req));
+ pool_put (h1m->req_pool[hc->c_thread_index], req);
+ hc->flags &= ~HTTP_CONN_F_HAS_REQUEST;
+}
+
static void
http1_send_error (http_conn_t *hc, http_status_code_t ec,
transport_send_params_t *sp)
@@ -730,13 +807,13 @@ http1_target_fixup (http_conn_t *hc, http_req_t *req)
}
static void
-http1_write_app_headers (http_conn_t *hc, http_msg_t *msg, u8 **tx_buf)
+http1_write_app_headers (http_req_t *req, http_msg_t *msg, u8 **tx_buf)
{
u8 *app_headers, *p, *end;
u32 *tmp;
/* read app header list */
- app_headers = http_get_app_header_list (hc, msg);
+ app_headers = http_get_app_header_list (req, msg);
/* serialize app headers to tx_buf */
end = app_headers + msg->data.headers_len;
@@ -871,8 +948,8 @@ http1_req_state_wait_transport_reply (http_conn_t *hc, http_req_t *req,
error:
http_io_ts_drain_all (hc);
http_io_ts_after_read (hc, 1);
- session_transport_closing_notify (&hc->connection);
- session_transport_closed_notify (&hc->connection);
+ session_transport_closing_notify (&req->connection);
+ session_transport_closed_notify (&req->connection);
http_disconnect_transport (hc);
return HTTP_SM_ERROR;
}
@@ -978,7 +1055,7 @@ error:
http_io_ts_drain_all (hc);
http_io_ts_after_read (hc, 1);
http1_send_error (hc, ec, 0);
- session_transport_closing_notify (&hc->connection);
+ session_transport_closing_notify (&req->connection);
http_disconnect_transport (hc);
return HTTP_SM_ERROR;
@@ -1015,7 +1092,7 @@ http1_req_state_transport_io_more_data (http_conn_t *hc, http_req_t *req,
if (n_written > req->to_recv)
{
clib_warning ("http protocol error: received more data than expected");
- session_transport_closing_notify (&hc->connection);
+ session_transport_closing_notify (&req->connection);
http_disconnect_transport (hc);
http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD);
return HTTP_SM_ERROR;
@@ -1117,8 +1194,8 @@ http1_req_state_udp_tunnel_rx (http_conn_t *hc, http_req_t *req,
{
/* capsule datagram is invalid (session need to be aborted) */
http_io_ts_drain_all (hc);
- session_transport_closing_notify (&hc->connection);
- session_transport_closed_notify (&hc->connection);
+ session_transport_closing_notify (&req->connection);
+ session_transport_closed_notify (&req->connection);
http_disconnect_transport (hc);
return HTTP_SM_STOP;
}
@@ -1262,7 +1339,7 @@ http1_req_state_wait_app_reply (http_conn_t *hc, http_req_t *req,
if (msg.data.headers_len)
{
HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
- http1_write_app_headers (hc, &msg, &response);
+ http1_write_app_headers (req, &msg, &response);
}
/* Add empty line after headers */
response = format (response, "\r\n");
@@ -1297,7 +1374,7 @@ http1_req_state_wait_app_reply (http_conn_t *hc, http_req_t *req,
error:
http1_send_error (hc, sc, sp);
- session_transport_closing_notify (&hc->connection);
+ session_transport_closing_notify (&req->connection);
http_disconnect_transport (hc);
return HTTP_SM_STOP;
}
@@ -1392,7 +1469,7 @@ http1_req_state_wait_app_method (http_conn_t *hc, http_req_t *req,
if (msg.data.headers_len)
{
HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
- http1_write_app_headers (hc, &msg, &request);
+ http1_write_app_headers (req, &msg, &request);
}
/* Add empty line after headers */
request = format (request, "\r\n");
@@ -1414,8 +1491,8 @@ http1_req_state_wait_app_method (http_conn_t *hc, http_req_t *req,
error:
http_io_as_drain_all (req);
- session_transport_closing_notify (&hc->connection);
- session_transport_closed_notify (&hc->connection);
+ session_transport_closing_notify (&req->connection);
+ session_transport_closed_notify (&req->connection);
http_disconnect_transport (hc);
done:
@@ -1617,20 +1694,69 @@ http1_req_run_state_machine (http_conn_t *hc, http_req_t *req,
/* http core VFT */
/*****************/
-static void
-http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp)
+static u32
+http1_hc_index_get_by_req_index (u32 req_index, u32 thread_index)
{
http_req_t *req;
- req = http_get_req_if_valid (hc, 0);
- if (!req)
+ req = http1_req_get (req_index, thread_index);
+ return req->hr_hc_index;
+}
+
+static transport_connection_t *
+http1_req_get_connection (u32 req_index, u32 thread_index)
+{
+ http_req_t *req;
+ req = http1_req_get (req_index, thread_index);
+ return &req->connection;
+}
+
+static u8 *
+format_http1_req (u8 *s, va_list *args)
+{
+ http_req_t *req = va_arg (*args, http_req_t *);
+ http_conn_t *hc = va_arg (*args, http_conn_t *);
+ session_t *ts;
+
+ ts = session_get_from_handle (hc->hc_tc_session_handle);
+ s = format (s, "[%d:%d][H1] app_wrk %u hc_index %u ts %d:%d",
+ req->c_thread_index, req->c_s_index, req->hr_pa_wrk_index,
+ req->hr_hc_index, ts->thread_index, ts->session_index);
+
+ return s;
+}
+
+static u8 *
+http1_format_req (u8 *s, va_list *args)
+{
+ u32 req_index = va_arg (*args, u32);
+ u32 thread_index = va_arg (*args, u32);
+ http_conn_t *hc = va_arg (*args, http_conn_t *);
+ u32 verbose = va_arg (*args, u32);
+ http_req_t *req;
+
+ req = http1_req_get (req_index, thread_index);
+
+ s = format (s, "%-" SESSION_CLI_ID_LEN "U", format_http1_req, req, hc);
+ if (verbose)
{
- http_alloc_req (hc);
- req = http_get_req (hc, 0);
- req->app_session_handle = hc->h_pa_session_handle;
- http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD);
+ s =
+ format (s, "%-" SESSION_CLI_STATE_LEN "U", format_http_conn_state, hc);
+ if (verbose > 1)
+ s = format (s, "\n");
}
+ return s;
+}
+
+static void
+http1_app_tx_callback (http_conn_t *hc, u32 req_index,
+ transport_send_params_t *sp)
+{
+ http_req_t *req;
+
+ req = http1_req_get (req_index, hc->c_thread_index);
+
if (!http1_req_state_is_tx_valid (req))
{
/* Sometimes the server apps can send the response earlier
@@ -1645,7 +1771,7 @@ http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp)
{
clib_warning ("hc [%u]%x invalid tx state: http req state "
"'%U', session state '%U'",
- hc->c_thread_index, hc->h_hc_index,
+ hc->c_thread_index, hc->hc_hc_index,
format_http_req_state, req->state,
format_http_conn_state, hc);
http_io_as_drain_all (req);
@@ -1658,26 +1784,32 @@ http1_app_tx_callback (http_conn_t *hc, transport_send_params_t *sp)
}
static void
-http1_app_rx_evt_callback (http_conn_t *hc)
+http1_app_rx_evt_callback (http_conn_t *hc, u32 req_index, u32 thread_index)
{
http_req_t *req;
- req = http_get_req (hc, 0);
+ req = http1_req_get (req_index, thread_index);
if (req->state == HTTP_REQ_STATE_TUNNEL)
http1_req_state_tunnel_rx (hc, req, 0);
}
static void
-http1_app_close_callback (http_conn_t *hc)
+http1_app_close_callback (http_conn_t *hc, u32 req_index, u32 thread_index)
{
http_req_t *req;
- req = http_get_req_if_valid (hc, 0);
+ req = http1_req_get_if_valid (req_index, thread_index);
+ if (!req)
+ {
+ HTTP_DBG (1, "req already deleted");
+ return;
+ }
/* Nothing more to send, confirm close */
- if (!req || !http_io_as_max_read (req))
+ if (!http_io_as_max_read (req))
{
- session_transport_closed_notify (&hc->connection);
+ HTTP_DBG (1, "nothing more to send, confirm close");
+ session_transport_closed_notify (&req->connection);
http_disconnect_transport (hc);
}
else
@@ -1688,31 +1820,48 @@ http1_app_close_callback (http_conn_t *hc)
}
static void
-http1_app_reset_callback (http_conn_t *hc)
+http1_app_reset_callback (http_conn_t *hc, u32 req_index, u32 thread_index)
{
- session_transport_closed_notify (&hc->connection);
+ http_req_t *req;
+ req = http1_req_get (req_index, thread_index);
+ session_transport_closed_notify (&req->connection);
http_disconnect_transport (hc);
}
+static int
+http1_transport_connected_callback (http_conn_t *hc)
+{
+ http_req_t *req;
+
+ ASSERT (hc->flags & HTTP_CONN_F_NO_APP_SESSION);
+
+ req = http1_conn_alloc_req (hc);
+ http_req_state_change (req, HTTP_REQ_STATE_WAIT_APP_METHOD);
+ return http_conn_established (hc, req);
+}
+
static void
http1_transport_rx_callback (http_conn_t *hc)
{
http_req_t *req;
- req = http_get_req_if_valid (hc, 0);
- if (!req)
+ if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
{
- http_alloc_req (hc);
- req = http_get_req (hc, 0);
- req->app_session_handle = hc->h_pa_session_handle;
+ ASSERT (hc->flags & HTTP_CONN_F_IS_SERVER);
+ /* first request - create request ctx and notify app about new conn */
+ req = http1_conn_alloc_req (hc);
+ http_conn_accept_request (hc, req);
http_req_state_change (req, HTTP_REQ_STATE_WAIT_TRANSPORT_METHOD);
+ hc->flags &= ~HTTP_CONN_F_NO_APP_SESSION;
}
+ else
+ req = http1_conn_get_req (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->h_hc_index, format_http_req_state,
+ 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;
@@ -1725,18 +1874,74 @@ http1_transport_rx_callback (http_conn_t *hc)
static void
http1_transport_close_callback (http_conn_t *hc)
{
+ if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
+ return;
/* Nothing more to rx, propagate to app */
if (!http_io_ts_max_read (hc))
- session_transport_closing_notify (&hc->connection);
+ {
+ http_req_t *req = http1_conn_get_req (hc);
+ session_transport_closing_notify (&req->connection);
+ }
+}
+
+static void
+http1_transport_reset_callback (http_conn_t *hc)
+{
+ if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
+ return;
+ http_req_t *req = http1_conn_get_req (hc);
+ session_transport_reset_notify (&req->connection);
+}
+
+static void
+http1_transport_conn_reschedule_callback (http_conn_t *hc)
+{
+ ASSERT (hc->flags & HTTP_CONN_F_HAS_REQUEST);
+ http_req_t *req = http1_conn_get_req (hc);
+ transport_connection_reschedule (&req->connection);
+}
+
+static void
+http1_conn_cleanup_callback (http_conn_t *hc)
+{
+ http_req_t *req;
+ if (!(hc->flags & HTTP_CONN_F_HAS_REQUEST))
+ return;
+
+ req = http1_conn_get_req (hc);
+ session_transport_delete_notify (&req->connection);
+ http1_conn_free_req (hc);
+}
+
+static void
+http1_enable_callback (void)
+{
+ http1_main_t *h1m = &http1_main;
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
+ u32 num_threads;
+
+ num_threads = 1 /* main thread */ + vtm->n_threads;
+
+ vec_validate (h1m->req_pool, num_threads - 1);
}
const static http_engine_vft_t http1_engine = {
+ .name = "http1",
+ .hc_index_get_by_req_index = http1_hc_index_get_by_req_index,
+ .req_get_connection = http1_req_get_connection,
+ .format_req = http1_format_req,
.app_tx_callback = http1_app_tx_callback,
.app_rx_evt_callback = http1_app_rx_evt_callback,
.app_close_callback = http1_app_close_callback,
.app_reset_callback = http1_app_reset_callback,
+ .transport_connected_callback = http1_transport_connected_callback,
.transport_rx_callback = http1_transport_rx_callback,
.transport_close_callback = http1_transport_close_callback,
+ .transport_conn_reschedule_callback =
+ http1_transport_conn_reschedule_callback,
+ .transport_reset_callback = http1_transport_reset_callback,
+ .conn_cleanup_callback = http1_conn_cleanup_callback,
+ .enable_callback = http1_enable_callback,
};
static clib_error_t *