http_static: resize header response buffer if needed 92/42392/8
authorSemir Sionek <[email protected]>
Wed, 26 Feb 2025 16:50:23 +0000 (11:50 -0500)
committerFlorin Coras <[email protected]>
Mon, 10 Mar 2025 20:30:23 +0000 (20:30 +0000)
Type: fix

Change-Id: If77469fbdf2b95b0c546a2d1de1cc8663464e1fc
Signed-off-by: Semir Sionek <[email protected]>
src/plugins/http/http.h
src/plugins/http_static/static_server.c

index 1d2a949..434ff96 100644 (file)
@@ -934,21 +934,24 @@ http_init_headers_ctx (http_headers_ctx_t *ctx, u8 *buf, u32 len)
  * @param name      Header name ID (see @ref http_header_name_t).
  * @param value     Header value pointer.
  * @param value_len Header value length.
+ *
+ * @return @c 0 if in case of success, @c -1 otherwise.
  */
-always_inline void
+always_inline int
 http_add_header (http_headers_ctx_t *ctx, http_header_name_t name,
                 const char *value, uword value_len)
 {
   http_app_header_t *header;
 
-  ASSERT ((ctx->tail_offset + sizeof (http_app_header_t) + value_len) <
-         ctx->len);
+  if ((ctx->tail_offset + sizeof (http_app_header_t) + value_len) > ctx->len)
+    return -1;
 
   header = (http_app_header_t *) (ctx->buf + ctx->tail_offset);
   header->name = (u32) name;
   header->value.len = (u32) value_len;
   clib_memcpy (header->value.token, (u8 *) value, value_len);
   ctx->tail_offset += sizeof (http_app_header_t) + value_len;
+  return 0;
 }
 
 /**
@@ -959,15 +962,18 @@ http_add_header (http_headers_ctx_t *ctx, http_header_name_t name,
  * @param name_len  Header name length.
  * @param value     Header value pointer.
  * @param value_len Header value length.
+ *
+ * @return @c 0 if in case of success, @c -1 otherwise.
  */
-always_inline void
+always_inline int
 http_add_custom_header (http_headers_ctx_t *ctx, const char *name,
                        uword name_len, const char *value, uword value_len)
 {
   http_custom_token_t *token;
 
-  ASSERT ((ctx->tail_offset + 2 * sizeof (http_custom_token_t) + name_len +
-          value_len) < ctx->len);
+  if ((ctx->tail_offset + 2 * sizeof (http_custom_token_t) + name_len +
+       value_len) > ctx->len)
+    return -1;
 
   /* name */
   token = (http_custom_token_t *) (ctx->buf + ctx->tail_offset);
@@ -980,6 +986,18 @@ http_add_custom_header (http_headers_ctx_t *ctx, const char *name,
   token->len = (u32) value_len;
   clib_memcpy (token->token, (u8 *) value, token->len);
   ctx->tail_offset += sizeof (http_custom_token_t) + value_len;
+  return 0;
+}
+
+/**
+ * Truncate the header list
+ *
+ * @param ctx Headers list context.
+ */
+always_inline void
+http_truncate_headers_list (http_headers_ctx_t *ctx)
+{
+  ctx->tail_offset = 0;
 }
 
 typedef enum http_uri_host_type_
index 9d416da..d7958fd 100644 (file)
 /*? %%clicmd:group_label Static HTTP Server %% ?*/
 
 #define HSS_FIFO_THRESH (16 << 10)
-
+#define HSS_HEADER_BUF_MAX_SIZE 16192
 hss_main_t hss_main;
 
+static int
+hss_add_header (hss_session_t *hs, http_header_name_t name, const char *value,
+               uword value_len)
+{
+  u32 needed_size = 0;
+  while (http_add_header (&hs->resp_headers, name, value, value_len) == -1)
+    {
+      if (needed_size)
+       {
+         http_truncate_headers_list (&hs->resp_headers);
+         hs->data_len = 0;
+         return -1;
+       }
+      else
+       needed_size = hs->resp_headers.tail_offset +
+                     sizeof (http_app_header_t) + value_len;
+      if (needed_size < HSS_HEADER_BUF_MAX_SIZE)
+       {
+         vec_resize (hs->headers_buf, sizeof (http_app_header_t) + value_len);
+         hs->resp_headers.len = needed_size;
+         hs->resp_headers.buf = hs->headers_buf;
+       }
+      else
+       {
+         http_truncate_headers_list (&hs->resp_headers);
+         hs->data_len = 0;
+         return -1;
+       }
+    }
+  return 0;
+}
+
 static hss_session_t *
 hss_session_alloc (u32 thread_index)
 {
@@ -175,8 +207,9 @@ hss_session_send_data (hss_url_handler_args_t *args)
 
   /* Set content type only if we have some response data */
   if (hs->data_len)
-    http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
-                    http_content_type_token (args->ct));
+    if (hss_add_header (hs, HTTP_HEADER_CONTENT_TYPE,
+                       http_content_type_token (args->ct)))
+      args->sc = HTTP_STATUS_INTERNAL_ERROR;
 
   start_send_data (hs, args->sc);
 }
@@ -305,8 +338,9 @@ try_url_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
 
   /* Set content type only if we have some response data */
   if (hs->data_len)
-    http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
-                    http_content_type_token (args.ct));
+    if (hss_add_header (hs, HTTP_HEADER_CONTENT_TYPE,
+                       http_content_type_token (args.ct)))
+      sc = HTTP_STATUS_INTERNAL_ERROR;
 
   start_send_data (hs, sc);
 
@@ -383,8 +417,10 @@ try_index_file (hss_main_t *hsm, hss_session_t *hs, u8 *path)
 
   vec_free (port_str);
 
-  http_add_header (&hs->resp_headers, HTTP_HEADER_LOCATION,
-                  (const char *) redirect, vec_len (redirect));
+  if (hss_add_header (hs, HTTP_HEADER_LOCATION, (const char *) redirect,
+                     vec_len (redirect)))
+    return HTTP_STATUS_INTERNAL_ERROR;
+
   vec_free (redirect);
   hs->data_len = 0;
   hs->free_data = 1;
@@ -463,13 +499,16 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
    * Last-Modified
    */
   type = content_type_from_request (target);
-  http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
-                  http_content_type_token (type));
-  http_add_header (&hs->resp_headers, HTTP_HEADER_CACHE_CONTROL,
-                  (const char *) hsm->max_age_formatted,
-                  vec_len (hsm->max_age_formatted));
-  http_add_header (&hs->resp_headers, HTTP_HEADER_LAST_MODIFIED,
-                  (const char *) last_modified, vec_len (last_modified));
+  if (hss_add_header (hs, HTTP_HEADER_CONTENT_TYPE,
+                     http_content_type_token (type)) ||
+      hss_add_header (hs, HTTP_HEADER_CACHE_CONTROL,
+                     (const char *) hsm->max_age_formatted,
+                     vec_len (hsm->max_age_formatted)) ||
+      hss_add_header (hs, HTTP_HEADER_LAST_MODIFIED,
+                     (const char *) last_modified, vec_len (last_modified)))
+    {
+      sc = HTTP_STATUS_INTERNAL_ERROR;
+    }
 
 done:
   vec_free (sanitized_path);
@@ -521,9 +560,10 @@ 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_ALLOW,
-                      http_token_lit ("GET, POST"));
-      start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
+      if (hss_add_header (hs, HTTP_HEADER_ALLOW, http_token_lit ("GET, POST")))
+       start_send_data (hs, HTTP_STATUS_INTERNAL_ERROR);
+      else
+       start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
       goto err_done;
     }