diff options
author | 2024-06-04 19:00:00 +0200 | |
---|---|---|
committer | 2024-06-13 06:35:26 +0000 | |
commit | 82ad9660becfcdd93c906d909d7e478733c5fbbe (patch) | |
tree | 9eb2615037a0e49d87ed73dc2ca8447eeeafc32c /src/plugins/hs_apps/http_cli.c | |
parent | eaa7d91ad77f9c6691b42b0e9f631166b4bcf44f (diff) |
http: return more than url to server app
Provide all bytes as received from transport as data in the http
message to server. Additionally provide offset and length of target
path, target query, headers and body. Offers apis for parsing of
headers, percent decoding, target path/query syntax verification.
Type: improvement
Change-Id: Idbe6f13afa378650cc5212ea7d3f9319183ebbbe
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/plugins/hs_apps/http_cli.c')
-rw-r--r-- | src/plugins/hs_apps/http_cli.c | 111 |
1 files changed, 85 insertions, 26 deletions
diff --git a/src/plugins/hs_apps/http_cli.c b/src/plugins/hs_apps/http_cli.c index f42f65342c3..4970da72012 100644 --- a/src/plugins/hs_apps/http_cli.c +++ b/src/plugins/hs_apps/http_cli.c @@ -18,11 +18,20 @@ #include <vnet/session/session.h> #include <http/http.h> +#define HCS_DEBUG 0 + +#if HCS_DEBUG +#define HCS_DBG(_fmt, _args...) clib_warning (_fmt, ##_args) +#else +#define HCS_DBG(_fmt, _args...) +#endif + typedef struct { u32 hs_index; u32 thread_index; u64 node_index; + u8 plain_text; u8 *buf; } hcs_cli_args_t; @@ -139,7 +148,8 @@ hcs_cli_output (uword arg, u8 *buffer, uword buffer_bytes) } static void -start_send_data (hcs_session_t *hs, http_status_code_t status) +start_send_data (hcs_session_t *hs, http_status_code_t status, + http_content_type_t type) { http_msg_t msg; session_t *ts; @@ -147,7 +157,7 @@ start_send_data (hcs_session_t *hs, http_status_code_t status) msg.type = HTTP_MSG_REPLY; msg.code = status; - msg.content_type = HTTP_CONTENT_TEXT_HTML; + msg.content_type = type; msg.data.type = HTTP_MSG_DATA_INLINE; msg.data.len = vec_len (hs->tx_buf); @@ -181,6 +191,7 @@ send_data_to_http (void *rpc_args) { hcs_cli_args_t *args = (hcs_cli_args_t *) rpc_args; hcs_session_t *hs; + http_content_type_t type = HTTP_CONTENT_TEXT_HTML; hs = hcs_session_get (args->thread_index, args->hs_index); if (!hs) @@ -190,7 +201,9 @@ send_data_to_http (void *rpc_args) } hs->tx_buf = args->buf; - start_send_data (hs, HTTP_STATUS_OK); + if (args->plain_text) + type = HTTP_CONTENT_TEXT_PLAIN; + start_send_data (hs, HTTP_STATUS_OK, type); cleanup: @@ -218,17 +231,9 @@ hcs_cli_process (vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f) { if (request[i] == '/') request[i] = ' '; - else if (request[i] == ' ') - { - /* vlib_cli_input is vector-based, no need for a NULL */ - vec_set_len (request, i); - break; - } i++; } - - /* Generate the html header */ - html = format (0, html_header_template, request /* title */ ); + HCS_DBG ("%v", request); /* Run the command */ unformat_init_vector (&input, vec_dup (request)); @@ -236,9 +241,17 @@ hcs_cli_process (vlib_main_t *vm, vlib_node_runtime_t *rt, vlib_frame_t *f) unformat_free (&input); request = 0; - /* Generate the html page */ - html = format (html, "%v", reply); - html = format (html, html_footer); + if (args->plain_text) + { + html = format (0, "%v", reply); + } + else + { + /* Generate the html page */ + html = format (0, html_header_template, request /* title */); + html = format (html, "%v", reply); + html = format (html, html_footer); + } /* Send it */ rpc_args = clib_mem_alloc (sizeof (*args)); @@ -308,9 +321,10 @@ hcs_ts_rx_callback (session_t *ts) hcs_cli_args_t args = {}; hcs_session_t *hs; http_msg_t msg; - int rv; + int rv, is_encoded = 0; hs = hcs_session_get (ts->thread_index, ts->opaque); + hs->tx_buf = 0; /* Read the http message header */ rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg); @@ -318,23 +332,65 @@ hcs_ts_rx_callback (session_t *ts) if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET) { - hs->tx_buf = 0; - start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED); - return 0; + start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED, + HTTP_CONTENT_TEXT_HTML); + goto done; } - if (msg.data.len == 0) + if (msg.data.target_path_len == 0 || + msg.data.target_form != HTTP_TARGET_ORIGIN_FORM) { hs->tx_buf = 0; - start_send_data (hs, HTTP_STATUS_BAD_REQUEST); - return 0; + start_send_data (hs, HTTP_STATUS_BAD_REQUEST, HTTP_CONTENT_TEXT_HTML); + goto done; } /* send the command to a new/recycled vlib process */ - vec_validate (args.buf, msg.data.len - 1); - rv = svm_fifo_dequeue (ts->rx_fifo, msg.data.len, args.buf); - ASSERT (rv == msg.data.len); - vec_set_len (args.buf, rv); + vec_validate (args.buf, msg.data.target_path_len - 1); + rv = svm_fifo_peek (ts->rx_fifo, msg.data.target_path_offset, + msg.data.target_path_len, args.buf); + ASSERT (rv == msg.data.target_path_len); + HCS_DBG ("%v", args.buf); + if (http_validate_abs_path_syntax (args.buf, &is_encoded)) + { + start_send_data (hs, HTTP_STATUS_BAD_REQUEST, HTTP_CONTENT_TEXT_HTML); + vec_free (args.buf); + goto done; + } + if (is_encoded) + { + u8 *decoded = http_percent_decode (args.buf); + vec_free (args.buf); + args.buf = decoded; + } + + if (msg.data.headers_len) + { + u8 *headers = 0; + http_header_table_t *ht; + vec_validate (headers, msg.data.headers_len - 1); + rv = svm_fifo_peek (ts->rx_fifo, msg.data.headers_offset, + msg.data.headers_len, headers); + ASSERT (rv == msg.data.headers_len); + if (http_parse_headers (headers, &ht)) + { + start_send_data (hs, HTTP_STATUS_BAD_REQUEST, + HTTP_CONTENT_TEXT_HTML); + vec_free (args.buf); + vec_free (headers); + goto done; + } + const char *accept_value = http_get_header (ht, HTTP_HEADER_ACCEPT); + if (accept_value) + { + HCS_DBG ("client accept: %s", accept_value); + /* just for testing purpose, we don't care about precedence */ + if (strstr (accept_value, "text/plain")) + args.plain_text = 1; + } + http_free_header_table (ht); + vec_free (headers); + } args.hs_index = hs->session_index; args.thread_index = ts->thread_index; @@ -345,6 +401,9 @@ hcs_ts_rx_callback (session_t *ts) sizeof (args)); else alloc_cli_process (&args); + +done: + svm_fifo_dequeue_drop (ts->rx_fifo, msg.data.len); return 0; } |