diff options
author | Matus Fabian <matfabia@cisco.com> | 2024-06-20 17:08:26 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-07-23 15:22:34 +0000 |
commit | 8ca6ce6fe1e65c8b57b9c0910dfd1243db0e49b9 (patch) | |
tree | da860f9fdeab192a4f90cc96c55bace986fef2a8 /src/plugins/http_static | |
parent | 1f870c9bdc4f2ce4076b1faeb42878a41125fd76 (diff) |
http: return more than data from server app
Server app could return headers in front of body/data buffer.
Offers apis for building and serialization of headers section.
HTTP layer now only add Date, Server and Content-Lengths headers,
rest is up to app. Well known header names are predefined.
Type: improvement
Change-Id: If778bdfc9acf6b0d11a48f0a745a3a56c96c2436
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/plugins/http_static')
-rw-r--r-- | src/plugins/http_static/builtinurl/json_urls.c | 3 | ||||
-rw-r--r-- | src/plugins/http_static/http_cache.c | 6 | ||||
-rw-r--r-- | src/plugins/http_static/http_static.h | 7 | ||||
-rw-r--r-- | src/plugins/http_static/static_server.c | 107 |
4 files changed, 97 insertions, 26 deletions
diff --git a/src/plugins/http_static/builtinurl/json_urls.c b/src/plugins/http_static/builtinurl/json_urls.c index 8578be147f3..19c5245e4b2 100644 --- a/src/plugins/http_static/builtinurl/json_urls.c +++ b/src/plugins/http_static/builtinurl/json_urls.c @@ -45,6 +45,7 @@ handle_get_version (hss_url_handler_args_t *args) args->data = s; args->data_len = vec_len (s); + args->ct = HTTP_CONTENT_APP_JSON; args->free_vec_data = 1; return HSS_URL_HANDLER_OK; } @@ -117,6 +118,7 @@ handle_get_interface_stats (hss_url_handler_args_t *args) out: args->data = s; args->data_len = vec_len (s); + args->ct = HTTP_CONTENT_APP_JSON; args->free_vec_data = 1; vec_free (sw_if_indices); vec_free (stats); @@ -157,6 +159,7 @@ handle_get_interface_list (hss_url_handler_args_t *args) args->data = s; args->data_len = vec_len (s); + args->ct = HTTP_CONTENT_APP_JSON; args->free_vec_data = 1; return HSS_URL_HANDLER_OK; } diff --git a/src/plugins/http_static/http_cache.c b/src/plugins/http_static/http_cache.c index 8b9751b7f78..7a069dace00 100644 --- a/src/plugins/http_static/http_cache.c +++ b/src/plugins/http_static/http_cache.c @@ -421,19 +421,19 @@ format_hss_cache (u8 *s, va_list *args) { s = format (s, "cache size %lld bytes, limit %lld bytes, evictions %lld", hc->cache_size, hc->cache_limit, hc->cache_evictions); - return 0; + return s; } vm = vlib_get_main (); now = vlib_time_now (vm); - s = format (s, "%U", format_hss_cache_entry, 0 /* header */, now); + s = format (s, "%U\n", format_hss_cache_entry, 0 /* header */, now); for (index = hc->first_index; index != ~0;) { ce = pool_elt_at_index (hc->cache_pool, index); index = ce->next_index; - s = format (s, "%U", format_hss_cache_entry, ce, now); + s = format (s, "%U\n", format_hss_cache_entry, ce, now); } s = format (s, "%40s%12lld", "Total Size", hc->cache_size); diff --git a/src/plugins/http_static/http_static.h b/src/plugins/http_static/http_static.h index 8f336e83d58..4c22e1d7ed7 100644 --- a/src/plugins/http_static/http_static.h +++ b/src/plugins/http_static/http_static.h @@ -50,8 +50,10 @@ typedef struct int free_data; /** File cache pool index */ u32 cache_pool_index; - /** Content type, e.g. text, text/javascript, etc. */ - http_content_type_t content_type; + /** Response header list */ + http_header_t *resp_headers; + /** Serialized headers to send */ + u8 *headers_buf; } hss_session_t; typedef struct hss_session_handle_ @@ -91,6 +93,7 @@ typedef struct hss_url_handler_args_ uword data_len; u8 free_vec_data; http_status_code_t sc; + http_content_type_t ct; }; }; } hss_url_handler_args_t; diff --git a/src/plugins/http_static/static_server.c b/src/plugins/http_static/static_server.c index 26224989332..bc18875626e 100644 --- a/src/plugins/http_static/static_server.c +++ b/src/plugins/http_static/static_server.c @@ -19,6 +19,9 @@ #include <sys/stat.h> #include <unistd.h> +#include <http/http_header_names.h> +#include <http/http_content_types.h> + /** @file static_server.c * Static http server, sufficient to serve .html / .css / .js content. */ @@ -83,34 +86,65 @@ start_send_data (hss_session_t *hs, http_status_code_t status) { http_msg_t msg; session_t *ts; + u8 *headers_buf = 0; int rv; ts = session_get (hs->vpp_session_index, hs->thread_index); + if (vec_len (hs->resp_headers)) + { + headers_buf = http_serialize_headers (hs->resp_headers); + vec_free (hs->resp_headers); + msg.data.headers_offset = 0; + msg.data.headers_len = vec_len (headers_buf); + } + else + { + msg.data.headers_offset = 0; + msg.data.headers_len = 0; + } + msg.type = HTTP_MSG_REPLY; msg.code = status; - msg.content_type = hs->content_type; - msg.data.len = hs->data_len; + msg.data.body_len = hs->data_len; + msg.data.len = msg.data.body_len + msg.data.headers_len; - if (hs->data_len > hss_main.use_ptr_thresh) + if (msg.data.len > hss_main.use_ptr_thresh) { msg.data.type = HTTP_MSG_DATA_PTR; rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg); ASSERT (rv == sizeof (msg)); + if (msg.data.headers_len) + { + hs->headers_buf = headers_buf; + uword headers = pointer_to_uword (hs->headers_buf); + rv = + svm_fifo_enqueue (ts->tx_fifo, sizeof (headers), (u8 *) &headers); + ASSERT (rv == sizeof (headers)); + } + uword data = pointer_to_uword (hs->data); rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (data), (u8 *) &data); - ASSERT (rv == sizeof (sizeof (data))); + ASSERT (rv == sizeof (data)); goto done; } msg.data.type = HTTP_MSG_DATA_INLINE; + msg.data.body_offset = msg.data.headers_len; rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg); ASSERT (rv == sizeof (msg)); - if (!msg.data.len) + 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); + } + + if (!msg.data.body_len) goto done; rv = svm_fifo_enqueue (ts->tx_fifo, hs->data_len, hs->data); @@ -142,6 +176,15 @@ hss_session_send_data (hss_url_handler_args_t *args) hs->data = args->data; hs->data_len = args->data_len; hs->free_data = args->free_vec_data; + + /* Set content type only if we have some response data */ + if (hs->data_len) + { + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_CONTENT_TYPE), + http_content_type_token (args->ct)); + } + start_send_data (hs, args->sc); } @@ -217,7 +260,6 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, http_status_code_t sc = HTTP_STATUS_OK; hss_url_handler_args_t args = {}; uword *p, *url_table; - http_content_type_t type; int rv; if (!hsm->enable_url_handlers || !target_path) @@ -229,8 +271,6 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, target_path = format (target_path, "index.html"); } - type = content_type_from_request (target_path); - /* Look for built-in GET / POST handlers */ url_table = (rt == HTTP_REQ_GET) ? hsm->get_url_handlers : hsm->post_url_handlers; @@ -263,17 +303,24 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, { clib_warning ("builtin handler %llx hit on %s '%s' but failed!", p[0], (rt == HTTP_REQ_GET) ? "GET" : "POST", target_path); - sc = HTTP_STATUS_NOT_FOUND; + sc = HTTP_STATUS_BAD_GATEWAY; } hs->data = args.data; hs->data_len = args.data_len; hs->free_data = args.free_vec_data; - hs->content_type = type; + + /* Set content type only if we have some response data */ + if (hs->data_len) + { + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_CONTENT_TYPE), + http_content_type_token (args.ct)); + } start_send_data (hs, sc); - if (!hs->data) + if (!hs->data_len) hss_session_disconnect_transport (hs); return 0; @@ -337,18 +384,20 @@ try_index_file (hss_main_t *hsm, hss_session_t *hs, u8 *path) } redirect = - format (0, - "Location: http%s://%U%s%s\r\n\r\n", - proto == TRANSPORT_PROTO_TLS ? "s" : "", format_ip46_address, - &endpt.ip, endpt.is_ip4, print_port ? port_str : (u8 *) "", path); + format (0, "http%s://%U%s%s", proto == TRANSPORT_PROTO_TLS ? "s" : "", + format_ip46_address, &endpt.ip, endpt.is_ip4, + print_port ? port_str : (u8 *) "", path); if (hsm->debug_level > 0) clib_warning ("redirect: %s", redirect); vec_free (port_str); - hs->data = redirect; - hs->data_len = vec_len (redirect); + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_LOCATION), + (const char *) redirect, vec_len (redirect)); + hs->data = redirect; /* TODO: find better way */ + hs->data_len = 0; hs->free_data = 1; return HTTP_STATUS_MOVED; @@ -367,8 +416,6 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, if (!hsm->www_root) return -1; - type = content_type_from_request (target); - /* Remove dot segments to prevent path traversal */ sanitized_path = http_path_remove_dot_segments (target); @@ -420,11 +467,23 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt, hs->path = path; hs->cache_pool_index = ce_index; + /* Set following headers only for happy path: + * Content-Type + * Cache-Control max-age + */ + type = content_type_from_request (target); + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_CONTENT_TYPE), + http_content_type_token (type)); + /* TODO configurable max-age value */ + http_add_header (&hs->resp_headers, + http_header_name_token (HTTP_HEADER_CACHE_CONTROL), + http_token_lit ("max-age=600")); + done: vec_free (sanitized_path); - hs->content_type = type; start_send_data (hs, sc); - if (!hs->data) + if (!hs->data_len) hss_session_disconnect_transport (hs); return 0; @@ -459,6 +518,8 @@ hss_ts_rx_callback (session_t *ts) if (hs->free_data) vec_free (hs->data); hs->data = 0; + hs->resp_headers = 0; + vec_free (hs->headers_buf); /* Read the http message header */ rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg); @@ -467,6 +528,9 @@ hss_ts_rx_callback (session_t *ts) if (msg.type != HTTP_MSG_REQUEST || (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")); start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED); goto done; } @@ -648,6 +712,7 @@ hss_ts_cleanup (session_t *s, session_cleanup_ntf_t ntf) hs->data = 0; hs->data_offset = 0; hs->free_data = 0; + vec_free (hs->headers_buf); vec_free (hs->path); hss_session_free (hs); |