diff options
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; } |