http: move header serialization to http transport 36/42236/5
authorMatus Fabian <[email protected]>
Wed, 22 Jan 2025 15:31:22 +0000 (10:31 -0500)
committerFlorin Coras <[email protected]>
Thu, 23 Jan 2025 18:28:21 +0000 (18:28 +0000)
Apps called http_serialize_headers, which creates plain text buffer,
this is now hidden in http transport layer and apps pass headers in
generic form, so they can be encoded based on http version.

Type: improvement

Change-Id: Ie4fa0516cd3406d60f956751c8ee7ab40e633fa4
Signed-off-by: Matus Fabian <[email protected]>
12 files changed:
src/plugins/hs_apps/http_cli.c
src/plugins/hs_apps/http_client.c
src/plugins/hs_apps/http_client_cli.c
src/plugins/hs_apps/http_tps.c
src/plugins/hs_apps/proxy.c
src/plugins/hs_apps/proxy.h
src/plugins/hs_apps/vcl/vcl_test_protos.c
src/plugins/http/http.c
src/plugins/http/http.h
src/plugins/http/http_plugin.rst
src/plugins/http_static/http_static.h
src/plugins/http_static/static_server.c

index d670ae6..531e275 100644 (file)
@@ -52,7 +52,8 @@ typedef struct
   u32 tx_offset;
   u32 vpp_session_index;
   http_header_table_t req_headers;
-  http_header_t *resp_headers;
+  http_headers_ctx_t resp_headers;
+  u8 *resp_headers_buf;
 } hcs_session_t;
 
 typedef struct
@@ -92,6 +93,7 @@ hcs_session_alloc (u32 thread_index)
   memset (hs, 0, sizeof (*hs));
   hs->session_index = hs - hcm->sessions[thread_index];
   hs->thread_index = thread_index;
+  vec_validate (hs->resp_headers_buf, 255);
   return hs;
 }
 
@@ -172,21 +174,10 @@ start_send_data (hcs_session_t *hs, http_status_code_t status)
 {
   http_msg_t msg;
   session_t *ts;
-  u8 *headers_buf = 0;
   int rv;
 
-  if (vec_len (hs->resp_headers))
-    {
-      headers_buf = http_serialize_headers (hs->resp_headers);
-      vec_reset_length (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.data.headers_offset = 0;
+  msg.data.headers_len = hs->resp_headers.tail_offset;
 
   msg.type = HTTP_MSG_REPLY;
   msg.code = status;
@@ -201,9 +192,9 @@ start_send_data (hcs_session_t *hs, http_status_code_t status)
 
   if (msg.data.headers_len)
     {
-      rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf);
+      rv = svm_fifo_enqueue (ts->tx_fifo, msg.data.headers_len,
+                            hs->resp_headers.buf);
       ASSERT (rv == msg.data.headers_len);
-      vec_free (headers_buf);
     }
 
   if (!msg.data.body_len)
@@ -245,8 +236,7 @@ send_data_to_http (void *rpc_args)
   if (args->plain_text)
     type = HTTP_CONTENT_TEXT_PLAIN;
 
-  http_add_header (&hs->resp_headers,
-                  http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+  http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
                   http_content_type_token (type));
 
   start_send_data (hs, HTTP_STATUS_OK);
@@ -371,7 +361,8 @@ hcs_ts_rx_callback (session_t *ts)
 
   hs = hcs_session_get (ts->thread_index, ts->opaque);
   hs->tx_buf = 0;
-  vec_reset_length (hs->resp_headers);
+  http_init_headers_ctx (&hs->resp_headers, hs->resp_headers_buf,
+                        vec_len (hs->resp_headers_buf));
   http_reset_header_table (&hs->req_headers);
 
   /* Read the http message header */
@@ -380,8 +371,7 @@ hcs_ts_rx_callback (session_t *ts)
 
   if (msg.type != HTTP_MSG_REQUEST || msg.method_type != HTTP_REQ_GET)
     {
-      http_add_header (&hs->resp_headers,
-                      http_header_name_token (HTTP_HEADER_ALLOW),
+      http_add_header (&hs->resp_headers, HTTP_HEADER_ALLOW,
                       http_token_lit ("GET"));
       start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
       goto done;
@@ -540,7 +530,7 @@ hcs_ts_cleanup_callback (session_t *s, session_cleanup_ntf_t ntf)
     return;
 
   vec_free (hs->tx_buf);
-  vec_free (hs->resp_headers);
+  vec_free (hs->resp_headers_buf);
   http_free_header_table (&hs->req_headers);
   hcs_session_free (hs);
 }
index 91ac6cf..20271fc 100644 (file)
@@ -6,7 +6,6 @@
 #include <vnet/session/application_interface.h>
 #include <vnet/session/session.h>
 #include <http/http.h>
-#include <http/http_header_names.h>
 #include <http/http_content_types.h>
 #include <http/http_status_codes.h>
 #include <vppinfra/unix.h>
@@ -34,7 +33,7 @@ typedef struct
   u32 thread_index;
   vlib_main_t *vlib_main;
   u8 *headers_buf;
-  http_header_t *req_headers;
+  http_headers_ctx_t req_headers;
   http_msg_t msg;
 } hc_worker_t;
 
@@ -155,9 +154,9 @@ hc_request (session_t *s, session_error_t err)
   rv = svm_fifo_enqueue (s->tx_fifo, vec_len (hcm->target), hcm->target);
   ASSERT (rv == vec_len (hcm->target));
 
-  rv = svm_fifo_enqueue (s->tx_fifo, vec_len (wrk->headers_buf),
+  rv = svm_fifo_enqueue (s->tx_fifo, wrk->req_headers.tail_offset,
                         wrk->headers_buf);
-  ASSERT (rv == wrk->msg.data.headers_len);
+  ASSERT (rv == wrk->req_headers.tail_offset);
 
   if (hcm->req_method == HTTP_REQ_POST)
     {
@@ -214,22 +213,22 @@ hc_session_connected_callback (u32 app_index, u32 hc_session_index,
     {
       if (hcm->is_file)
        http_add_header (
-         &wrk->req_headers, http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+         &wrk->req_headers, HTTP_HEADER_CONTENT_TYPE,
          http_content_type_token (HTTP_CONTENT_APP_OCTET_STREAM));
       else
        http_add_header (
-         &wrk->req_headers, http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+         &wrk->req_headers, HTTP_HEADER_CONTENT_TYPE,
          http_content_type_token (HTTP_CONTENT_APP_X_WWW_FORM_URLENCODED));
     }
+  http_add_header (&wrk->req_headers, HTTP_HEADER_ACCEPT, "*", 1);
 
   vec_foreach (header, hcm->custom_header)
-    http_add_header (&wrk->req_headers, (const char *) header->name,
-                    vec_len (header->name), (const char *) header->value,
-                    vec_len (header->value));
-
-  wrk->headers_buf = http_serialize_headers (wrk->req_headers);
-  vec_free (wrk->req_headers);
+    http_add_custom_header (
+      &wrk->req_headers, (const char *) header->name, vec_len (header->name),
+      (const char *) header->value, vec_len (header->value));
 
+  clib_warning ("%U", format_http_bytes, wrk->headers_buf,
+               wrk->req_headers.tail_offset);
   wrk->msg.method_type = hcm->req_method;
   if (hcm->req_method == HTTP_REQ_POST)
     wrk->msg.data.body_len = vec_len (hcm->data);
@@ -240,7 +239,7 @@ hc_session_connected_callback (u32 app_index, u32 hc_session_index,
   /* request target */
   wrk->msg.data.target_path_len = vec_len (hcm->target);
   /* custom headers */
-  wrk->msg.data.headers_len = vec_len (wrk->headers_buf);
+  wrk->msg.data.headers_len = wrk->req_headers.tail_offset;
   /* total length */
   wrk->msg.data.len = wrk->msg.data.target_path_len +
                      wrk->msg.data.headers_len + wrk->msg.data.body_len;
@@ -621,7 +620,13 @@ hc_run (vlib_main_t *vm)
   num_threads = 1 /* main thread */ + vtm->n_threads;
   vec_validate (hcm->wrk, num_threads - 1);
   vec_foreach (wrk, hcm->wrk)
-    wrk->thread_index = wrk - hcm->wrk;
+    {
+      wrk->thread_index = wrk - hcm->wrk;
+      /* 4k for headers should be enough */
+      vec_validate (wrk->headers_buf, 4095);
+      http_init_headers_ctx (&wrk->req_headers, wrk->headers_buf,
+                            vec_len (wrk->headers_buf));
+    }
 
   if ((err = hc_attach ()))
     return clib_error_return (0, "http client attach: %U", format_clib_error,
index 3c50e24..4ee3b49 100644 (file)
@@ -16,7 +16,6 @@
 #include <vnet/session/application_interface.h>
 #include <vnet/session/session.h>
 #include <http/http.h>
-#include <http/http_header_names.h>
 #include <http/http_content_types.h>
 #include <http/http_status_codes.h>
 
@@ -37,7 +36,6 @@ typedef struct
   u32 vpp_session_index;
   u64 to_recv;
   u8 is_closed;
-  http_header_t *req_headers;
 } hcc_session_t;
 
 typedef struct
@@ -131,9 +129,10 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
   hcc_session_t *hs, *new_hs;
   hcc_worker_t *wrk;
   http_msg_t msg;
-  u8 *headers_buf;
+  u8 *headers_buf = 0;
   u32 new_hs_index;
   int rv;
+  http_headers_ctx_t headers;
 
   HCC_DBG ("ho hc_index: %d", hc_index);
 
@@ -157,11 +156,10 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
   HCC_DBG ("new hc_index: %d", new_hs->session_index);
   as->opaque = new_hs_index;
 
-  http_add_header (&new_hs->req_headers,
-                  http_header_name_token (HTTP_HEADER_ACCEPT),
+  vec_validate (headers_buf, 63);
+  http_init_headers_ctx (&headers, headers_buf, vec_len (headers_buf));
+  http_add_header (&headers, HTTP_HEADER_ACCEPT,
                   http_content_type_token (HTTP_CONTENT_TEXT_HTML));
-  headers_buf = http_serialize_headers (new_hs->req_headers);
-  vec_free (new_hs->req_headers);
 
   msg.type = HTTP_MSG_REQUEST;
   msg.method_type = HTTP_REQ_GET;
@@ -170,7 +168,7 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
   msg.data.target_path_len = vec_len (hcm->http_query);
   /* custom headers */
   msg.data.headers_offset = msg.data.target_path_len;
-  msg.data.headers_len = vec_len (headers_buf);
+  msg.data.headers_len = headers.tail_offset;
   /* request body */
   msg.data.body_len = 0;
   /* data type and total length */
@@ -180,7 +178,7 @@ hcc_ts_connected_callback (u32 app_index, u32 hc_index, session_t *as,
 
   svm_fifo_seg_t segs[3] = { { (u8 *) &msg, sizeof (msg) },
                             { hcm->http_query, vec_len (hcm->http_query) },
-                            { headers_buf, vec_len (headers_buf) } };
+                            { headers_buf, msg.data.headers_len } };
 
   rv = svm_fifo_enqueue_segments (as->tx_fifo, segs, 3, 0 /* allow partial */);
   vec_free (headers_buf);
index f4ef808..59a0309 100644 (file)
@@ -17,7 +17,6 @@
 #include <vnet/session/application_interface.h>
 #include <vnet/session/session.h>
 #include <http/http.h>
-#include <http/http_header_names.h>
 #include <http/http_content_types.h>
 
 #define HTS_RX_BUF_SIZE (64 << 10)
@@ -41,7 +40,8 @@ typedef struct
   };
   u8 *uri;
   u8 *rx_buf;
-  http_header_t *resp_headers;
+  http_headers_ctx_t resp_headers;
+  u8 *resp_headers_buf;
 } hts_session_t;
 
 typedef struct hts_listen_cfg_
@@ -86,6 +86,7 @@ hts_session_alloc (u32 thread_index)
   pool_get_zero (htm->sessions[thread_index], hs);
   hs->session_index = hs - htm->sessions[thread_index];
   hs->thread_index = thread_index;
+  vec_validate (hs->resp_headers_buf, 255);
 
   return hs;
 }
@@ -111,6 +112,7 @@ hts_session_free (hts_session_t *hs)
     clib_warning ("Freeing session %u", hs->session_index);
 
   vec_free (hs->rx_buf);
+  vec_free (hs->resp_headers_buf);
 
   if (CLIB_DEBUG)
     clib_memset (hs, 0xfa, sizeof (*hs));
@@ -233,26 +235,20 @@ hts_start_send_data (hts_session_t *hs, http_status_code_t status)
 {
   http_msg_t msg;
   session_t *ts;
-  u8 *headers_buf = 0;
   u32 n_segs = 1;
   svm_fifo_seg_t seg[2];
   int rv;
 
-  if (vec_len (hs->resp_headers))
+  msg.data.headers_offset = 0;
+  msg.data.headers_len = 0;
+
+  if (hs->resp_headers.tail_offset)
     {
-      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);
-      seg[1].data = headers_buf;
+      msg.data.headers_len = hs->resp_headers.tail_offset;
+      seg[1].data = hs->resp_headers_buf;
       seg[1].len = msg.data.headers_len;
       n_segs = 2;
     }
-  else
-    {
-      msg.data.headers_offset = 0;
-      msg.data.headers_len = 0;
-    }
 
   msg.type = HTTP_MSG_REPLY;
   msg.code = status;
@@ -266,7 +262,6 @@ hts_start_send_data (hts_session_t *hs, http_status_code_t status)
   ts = session_get (hs->vpp_session_index, hs->thread_index);
   rv = svm_fifo_enqueue_segments (ts->tx_fifo, seg, n_segs,
                                  0 /* allow partial */);
-  vec_free (headers_buf);
   ASSERT (rv == (sizeof (msg) + msg.data.headers_len));
 
   if (!msg.data.body_len)
@@ -320,8 +315,7 @@ try_test_file (hts_session_t *hs, u8 *target)
        }
     }
 
-  http_add_header (&hs->resp_headers,
-                  http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+  http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
                   http_content_type_token (HTTP_CONTENT_APP_OCTET_STREAM));
 
   hts_start_send_data (hs, HTTP_STATUS_OK);
@@ -380,9 +374,9 @@ hts_ts_rx_callback (session_t *ts)
   if (hs->left_recv == 0)
     {
       hs->data_len = 0;
-      hs->resp_headers = 0;
       hs->rx_buf = 0;
-
+      http_init_headers_ctx (&hs->resp_headers, hs->resp_headers_buf,
+                            vec_len (hs->resp_headers_buf));
       /* Read the http message header */
       rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
       ASSERT (rv == sizeof (msg));
@@ -394,8 +388,7 @@ hts_ts_rx_callback (session_t *ts)
        }
       if (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_add_header (&hs->resp_headers, HTTP_HEADER_ALLOW,
                           http_token_lit ("GET, POST"));
          hts_start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
          goto done;
index 38d96bb..1bcc1e8 100644 (file)
@@ -63,32 +63,39 @@ proxy_session_side_ctx_get (proxy_worker_t *wrk, u32 ctx_index)
 }
 
 static_always_inline void
-proxy_send_http_resp (session_t *s, http_status_code_t sc, u8 *headers_buf)
+proxy_send_http_resp (session_t *s, http_status_code_t sc,
+                     http_headers_ctx_t *headers)
 {
   http_msg_t msg;
   int rv;
   uword headers_ptr;
+  svm_fifo_seg_t seg[2];
+  u32 n_segs = 1;
 
   ASSERT (s->thread_index == vlib_get_thread_index ());
 
+  msg.data.headers_len = 0;
+  if (headers)
+    {
+      msg.data.headers_len = headers->tail_offset;
+      headers_ptr = pointer_to_uword (headers->buf);
+      seg[1].data = (u8 *) &headers_ptr;
+      seg[1].len = sizeof (headers_ptr);
+      n_segs = 2;
+    }
   msg.type = HTTP_MSG_REPLY;
   msg.code = sc;
   msg.data.type = HTTP_MSG_DATA_PTR;
-  msg.data.headers_len = vec_len (headers_buf);
   msg.data.len = msg.data.headers_len;
   msg.data.headers_offset = 0;
   msg.data.body_len = 0;
   msg.data.body_offset = 0;
+  seg[0].data = (u8 *) &msg;
+  seg[0].len = sizeof (msg);
 
-  headers_ptr = pointer_to_uword (headers_buf);
-  svm_fifo_seg_t seg[2] = {
-    { (u8 *) &msg, sizeof (msg) },
-    { (u8 *) &headers_ptr, sizeof (headers_ptr) },
-  };
-
-  rv = svm_fifo_enqueue_segments (s->tx_fifo, seg, msg.data.len ? 2 : 1,
-                                 0 /* allow partial */);
-  ASSERT (rv == (sizeof (msg) + (msg.data.len ? sizeof (headers_ptr) : 0)));
+  rv =
+    svm_fifo_enqueue_segments (s->tx_fifo, seg, n_segs, 0 /* allow partial */);
+  ASSERT (rv == (sizeof (msg) + (n_segs == 2 ? sizeof (headers_ptr) : 0)));
 
   if (svm_fifo_set_event (s->tx_fifo))
     session_program_tx_io_evt (s->handle, SESSION_IO_EVT_TX);
@@ -872,7 +879,7 @@ active_open_send_http_resp_rpc (void *arg)
        session_get_from_handle (ps->ao.session_handle));
       if (ao_tp == TRANSPORT_PROTO_UDP)
        proxy_send_http_resp (po_s, HTTP_STATUS_SWITCHING_PROTOCOLS,
-                             pm->capsule_proto_header);
+                             &pm->capsule_proto_header);
       else
        proxy_send_http_resp (po_s, HTTP_STATUS_OK, 0);
     }
@@ -1469,8 +1476,6 @@ VLIB_CLI_COMMAND (proxy_create_command, static) = {
 clib_error_t *
 proxy_main_init (vlib_main_t * vm)
 {
-  http_header_t *headers = 0;
-
   proxy_main_t *pm = &proxy_main;
   pm->server_client_index = ~0;
   pm->active_open_client_index = ~0;
@@ -1478,11 +1483,12 @@ proxy_main_init (vlib_main_t * vm)
   pm->idle_timeout = 600; /* connect-proxy default idle timeout 10 minutes */
   vec_validate (pm->client_sep, TRANSPORT_N_PROTOS - 1);
 
-  http_add_header (&headers,
-                  http_header_name_token (HTTP_HEADER_CAPSULE_PROTOCOL),
+  vec_validate (pm->capsule_proto_header_buf, 10);
+  http_init_headers_ctx (&pm->capsule_proto_header,
+                        pm->capsule_proto_header_buf,
+                        vec_len (pm->capsule_proto_header_buf));
+  http_add_header (&pm->capsule_proto_header, HTTP_HEADER_CAPSULE_PROTOCOL,
                   http_token_lit (HTTP_BOOLEAN_TRUE));
-  pm->capsule_proto_header = http_serialize_headers (headers);
-  vec_free (headers);
 
   return 0;
 }
index 814bebf..f26f4bf 100644 (file)
@@ -90,7 +90,8 @@ typedef struct
   u32 active_open_app_index;           /**< active open index after attach */
   u32 ckpair_index;                    /**< certkey pair index for tls */
 
-  u8 *capsule_proto_header;
+  http_headers_ctx_t capsule_proto_header;
+  u8 *capsule_proto_header_buf;
 
   /*
    * Configuration params
index da4b699..fd17c7b 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <hs_apps/vcl/vcl_test.h>
 #include <http/http.h>
-#include <http/http_header_names.h>
 #include <http/http_content_types.h>
 
 typedef enum vcl_test_http_state_
@@ -1162,7 +1161,7 @@ vt_process_http_client_write_msg (vcl_test_session_t *ts, void *buf,
                                  uint32_t nbytes)
 {
   http_msg_t msg;
-  http_header_t *req_headers = 0;
+  http_headers_ctx_t req_headers;
   u8 *headers_buf = 0;
   u8 *target;
   vcl_test_http_ctx_t *vcl_test_http_ctx = (vcl_test_http_ctx_t *) ts->opaque;
@@ -1207,11 +1206,11 @@ vt_process_http_client_write_msg (vcl_test_session_t *ts, void *buf,
 
   else if (PREDICT_FALSE (vcl_test_http_ctx->test_state == VCL_TEST_HTTP_IDLE))
     {
+      vec_validate (headers_buf, 63);
+      http_init_headers_ctx (&req_headers, headers_buf, vec_len (headers_buf));
       http_add_header (
-       &req_headers, http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+       &req_headers, HTTP_HEADER_CONTENT_TYPE,
        http_content_type_token (HTTP_CONTENT_APP_OCTET_STREAM));
-      headers_buf = http_serialize_headers (req_headers);
-      vec_free (req_headers);
 
       memset (&msg, 0, sizeof (http_msg_t));
       msg.type = HTTP_MSG_REQUEST;
@@ -1223,7 +1222,7 @@ vt_process_http_client_write_msg (vcl_test_session_t *ts, void *buf,
 
       /* headers */
       msg.data.headers_offset = msg.data.target_path_len;
-      msg.data.headers_len = vec_len (headers_buf);
+      msg.data.headers_len = req_headers.tail_offset;
 
       /* body */
       msg.data.body_offset = msg.data.headers_offset + msg.data.headers_len;
@@ -1236,7 +1235,7 @@ vt_process_http_client_write_msg (vcl_test_session_t *ts, void *buf,
       vppcom_data_segment_t segs[3] = { { (u8 *) &msg, sizeof (msg) },
                                        { target, strlen ((char *) target) },
                                        { headers_buf,
-                                         vec_len (headers_buf) } };
+                                         msg.data.headers_len } };
 
       do
        {
index 666f45c..69b661d 100644 (file)
@@ -468,14 +468,12 @@ static const char *connection_upgrade_template = "Connection: upgrade\r\n"
  */
 static const char *http_get_request_template = "GET %s HTTP/1.1\r\n"
                                               "Host: %v\r\n"
-                                              "User-Agent: %v\r\n"
-                                              "%s";
+                                              "User-Agent: %v\r\n";
 
 static const char *http_post_request_template = "POST %s HTTP/1.1\r\n"
                                                "Host: %v\r\n"
                                                "User-Agent: %v\r\n"
-                                               "Content-Length: %llu\r\n"
-                                               "%s";
+                                               "Content-Length: %llu\r\n";
 
 static u32
 http_send_data (http_conn_t *hc, u8 *data, u32 length)
@@ -1368,6 +1366,76 @@ error:
   return HTTP_SM_ERROR;
 }
 
+static void
+http_write_app_headers (http_conn_t *hc, http_msg_t *msg, u8 **tx_buf)
+{
+  http_main_t *hm = &http_main;
+  session_t *as;
+  u8 *app_headers, *p, *end;
+  u32 *tmp;
+  int rv;
+
+  as = session_get_from_handle (hc->h_pa_session_handle);
+
+  /* read app header list */
+  if (msg->data.type == HTTP_MSG_DATA_PTR)
+    {
+      uword app_headers_ptr;
+      rv = svm_fifo_dequeue (as->tx_fifo, sizeof (app_headers_ptr),
+                            (u8 *) &app_headers_ptr);
+      ASSERT (rv == sizeof (app_headers_ptr));
+      app_headers = uword_to_pointer (app_headers_ptr, u8 *);
+    }
+  else
+    {
+      app_headers = hm->app_header_lists[hc->c_thread_index];
+      rv = svm_fifo_dequeue (as->tx_fifo, msg->data.headers_len, app_headers);
+      ASSERT (rv == msg->data.headers_len);
+    }
+
+  /* serialize app headers to tx_buf */
+  end = app_headers + msg->data.headers_len;
+  while (app_headers < end)
+    {
+      /* custom header name? */
+      tmp = (u32 *) app_headers;
+      if (PREDICT_FALSE (*tmp & HTTP_CUSTOM_HEADER_NAME_BIT))
+       {
+         http_custom_token_t *name, *value;
+         name = (http_custom_token_t *) app_headers;
+         u32 name_len = name->len & ~HTTP_CUSTOM_HEADER_NAME_BIT;
+         app_headers += sizeof (http_custom_token_t) + name_len;
+         value = (http_custom_token_t *) app_headers;
+         app_headers += sizeof (http_custom_token_t) + value->len;
+         vec_add2 (*tx_buf, p, name_len + value->len + 4);
+         clib_memcpy (p, name->token, name_len);
+         p += name_len;
+         *p++ = ':';
+         *p++ = ' ';
+         clib_memcpy (p, value->token, value->len);
+         p += value->len;
+         *p++ = '\r';
+         *p++ = '\n';
+       }
+      else
+       {
+         http_app_header_t *header;
+         header = (http_app_header_t *) app_headers;
+         app_headers += sizeof (http_app_header_t) + header->value.len;
+         http_token_t name = { http_header_name_token (header->name) };
+         vec_add2 (*tx_buf, p, name.len + header->value.len + 4);
+         clib_memcpy (p, name.base, name.len);
+         p += name.len;
+         *p++ = ':';
+         *p++ = ' ';
+         clib_memcpy (p, header->value.token, header->value.len);
+         p += header->value.len;
+         *p++ = '\r';
+         *p++ = '\n';
+       }
+    }
+}
+
 static http_sm_result_t
 http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
 {
@@ -1407,6 +1475,8 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
       return HTTP_SM_ERROR;
     }
 
+  response = hm->tx_bufs[hc->c_thread_index];
+  vec_reset_length (response);
   /*
    * Add "protocol layer" headers:
    * - current time
@@ -1414,11 +1484,12 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
    * - data length
    */
   now = clib_timebase_now (&hm->timebase);
-  response = format (0, http_response_template, http_status_code_str[msg.code],
-                    /* Date */
-                    format_clib_timebase_time, now,
-                    /* Server */
-                    hc->app_name);
+  response =
+    format (response, http_response_template, http_status_code_str[msg.code],
+           /* Date */
+           format_clib_timebase_time, now,
+           /* Server */
+           hc->app_name);
 
   /* RFC9110 8.6: A server MUST NOT send Content-Length header field in a
    * 2xx (Successful) response to CONNECT or with a status code of 101
@@ -1449,28 +1520,10 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
   if (msg.data.headers_len)
     {
       HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
-      if (msg.data.type == HTTP_MSG_DATA_PTR)
-       {
-         uword app_headers_ptr;
-         rv = svm_fifo_dequeue (as->tx_fifo, sizeof (app_headers_ptr),
-                                (u8 *) &app_headers_ptr);
-         ASSERT (rv == sizeof (app_headers_ptr));
-         vec_append (response, uword_to_pointer (app_headers_ptr, u8 *));
-       }
-      else
-       {
-         u32 orig_len = vec_len (response);
-         vec_resize (response, msg.data.headers_len);
-         u8 *p = response + orig_len;
-         rv = svm_fifo_dequeue (as->tx_fifo, msg.data.headers_len, p);
-         ASSERT (rv == msg.data.headers_len);
-       }
-    }
-  else
-    {
-      /* No headers from app */
-      response = format (response, "\r\n");
+      http_write_app_headers (hc, &msg, &response);
     }
+  /* Add empty line after headers */
+  response = format (response, "\r\n");
   HTTP_DBG (3, "%v", response);
 
   sent = http_send_data (hc, response, vec_len (response));
@@ -1478,10 +1531,8 @@ http_req_state_wait_app_reply (http_conn_t *hc, transport_send_params_t *sp)
     {
       clib_warning ("sending status-line and headers failed!");
       sc = HTTP_STATUS_INTERNAL_ERROR;
-      vec_free (response);
       goto error;
     }
-  vec_free (response);
 
   if (msg.data.body_len)
     {
@@ -1513,6 +1564,7 @@ error:
 static http_sm_result_t
 http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
 {
+  http_main_t *hm = &http_main;
   http_msg_t msg;
   session_t *as;
   u8 *target_buff = 0, *request = 0, *target;
@@ -1556,6 +1608,8 @@ http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
       target = target_buff;
     }
 
+  request = hm->tx_bufs[hc->c_thread_index];
+  vec_reset_length (request);
   /* currently we support only GET and POST method */
   if (msg.method_type == HTTP_REQ_GET)
     {
@@ -1569,15 +1623,13 @@ http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
        * - host
        * - user agent
        */
-      request = format (0, http_get_request_template,
+      request = format (request, http_get_request_template,
                        /* target */
                        target,
                        /* Host */
                        hc->host,
                        /* User-Agent */
-                       hc->app_name,
-                       /* Any headers from app? */
-                       msg.data.headers_len ? "" : "\r\n");
+                       hc->app_name);
 
       next_state = HTTP_REQ_STATE_WAIT_TRANSPORT_REPLY;
       sm_result = HTTP_SM_STOP;
@@ -1595,7 +1647,7 @@ http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
        * - user agent
        * - content length
        */
-      request = format (0, http_post_request_template,
+      request = format (request, http_post_request_template,
                        /* target */
                        target,
                        /* Host */
@@ -1603,9 +1655,7 @@ http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
                        /* User-Agent */
                        hc->app_name,
                        /* Content-Length */
-                       msg.data.body_len,
-                       /* Any headers from app? */
-                       msg.data.headers_len ? "" : "\r\n");
+                       msg.data.body_len);
 
       http_buffer_init (&hc->req.tx_buf, msg_to_buf_type[msg.data.type],
                        as->tx_fifo, msg.data.body_len);
@@ -1623,23 +1673,10 @@ http_req_state_wait_app_method (http_conn_t *hc, transport_send_params_t *sp)
   if (msg.data.headers_len)
     {
       HTTP_DBG (0, "got headers from app, len %d", msg.data.headers_len);
-      if (msg.data.type == HTTP_MSG_DATA_PTR)
-       {
-         uword app_headers_ptr;
-         rv = svm_fifo_dequeue (as->tx_fifo, sizeof (app_headers_ptr),
-                                (u8 *) &app_headers_ptr);
-         ASSERT (rv == sizeof (app_headers_ptr));
-         vec_append (request, uword_to_pointer (app_headers_ptr, u8 *));
-       }
-      else
-       {
-         u32 orig_len = vec_len (request);
-         vec_resize (request, msg.data.headers_len);
-         u8 *p = request + orig_len;
-         rv = svm_fifo_dequeue (as->tx_fifo, msg.data.headers_len, p);
-         ASSERT (rv == msg.data.headers_len);
-       }
+      http_write_app_headers (hc, &msg, &request);
     }
+  /* Add empty line after headers */
+  request = format (request, "\r\n");
   HTTP_DBG (3, "%v", request);
 
   sent = http_send_data (hc, request, vec_len (request));
@@ -1661,7 +1698,6 @@ error:
 
 done:
   vec_free (target_buff);
-  vec_free (request);
   return sm_result;
 }
 
@@ -2297,6 +2333,7 @@ http_transport_enable (vlib_main_t *vm, u8 is_en)
   vec_validate (hm->wrk, num_threads - 1);
   vec_validate (hm->rx_bufs, num_threads - 1);
   vec_validate (hm->tx_bufs, num_threads - 1);
+  vec_validate (hm->app_header_lists, num_threads - 1);
   for (i = 0; i < num_threads; i++)
     {
       vec_validate (hm->rx_bufs[i],
@@ -2305,6 +2342,7 @@ http_transport_enable (vlib_main_t *vm, u8 is_en)
       vec_validate (hm->tx_bufs[i],
                    HTTP_UDP_PAYLOAD_MAX_LEN +
                      HTTP_UDP_PROXY_DATAGRAM_CAPSULE_OVERHEAD);
+      vec_validate (hm->app_header_lists[i], 32 << 10);
     }
 
   clib_timebase_init (&hm->timebase, 0 /* GMT */, CLIB_TIMEBASE_DAYLIGHT_NONE,
index 637452e..d61ac0b 100644 (file)
@@ -525,6 +525,7 @@ typedef struct http_main_
 
   u8 **rx_bufs;
   u8 **tx_bufs;
+  u8 **app_header_lists;
 
   clib_timebase_t timebase;
 
@@ -1135,65 +1136,72 @@ http_get_header (http_header_table_t *header_table, const char *name,
   return 0;
 }
 
-/**
- * Add header to the list.
- *
- * @param headers Header list.
- * @param name Pointer to header's name buffer.
- * @param name_len Length of the name.
- * @param value Pointer to header's value buffer.
- * @param value_len Length of the value.
- *
- * @note Headers added at protocol layer: Date, Server, Content-Length
- */
+typedef struct
+{
+  u32 len;        /**< length of the header data buffer */
+  u32 tail_offset; /**< current tail in header data */
+  u8 *buf;        /**< start of header data */
+} http_headers_ctx_t;
+
+typedef struct
+{
+  u32 len;
+  u8 token[0];
+} http_custom_token_t;
+
+typedef struct
+{
+  u32 name;
+  http_custom_token_t value;
+} http_app_header_t;
+
+/* Use high bit of header name length as custom header name bit. */
+#define HTTP_CUSTOM_HEADER_NAME_BIT (1 << 31)
+
 always_inline void
-http_add_header (http_header_t **headers, const char *name, uword name_len,
-                const char *value, uword value_len)
+http_init_headers_ctx (http_headers_ctx_t *ctx, u8 *buf, u32 len)
 {
-  http_header_t *header;
-  vec_add2 (*headers, header, 1);
-  header->name.base = (char *) name;
-  header->name.len = name_len;
-  header->value.base = (char *) value;
-  header->value.len = value_len;
+  ctx->len = len;
+  ctx->tail_offset = 0;
+  ctx->buf = buf;
 }
 
-/**
- * Serialize the header list.
- *
- * @param headers Header list to serialize.
- *
- * @return New vector with serialized headers.
- *
- * The caller is always responsible to free the returned vector.
- */
-always_inline u8 *
-http_serialize_headers (http_header_t *headers)
+always_inline void
+http_add_header (http_headers_ctx_t *ctx, http_header_name_t name,
+                const char *value, uword value_len)
 {
-  u8 *headers_buf = 0, *dst;
-  u32 headers_buf_len = 2;
-  http_header_t *header;
+  http_app_header_t *header;
 
-  vec_foreach (header, headers)
-    headers_buf_len += header->name.len + header->value.len + 4;
+  ASSERT ((ctx->tail_offset + sizeof (http_app_header_t) + value_len) <
+         ctx->len);
 
-  vec_validate (headers_buf, headers_buf_len - 1);
-  dst = headers_buf;
+  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;
+}
 
-  vec_foreach (header, headers)
-    {
-      clib_memcpy (dst, header->name.base, header->name.len);
-      dst += header->name.len;
-      *dst++ = ':';
-      *dst++ = ' ';
-      clib_memcpy (dst, header->value.base, header->value.len);
-      dst += header->value.len;
-      *dst++ = '\r';
-      *dst++ = '\n';
-    }
-  *dst++ = '\r';
-  *dst = '\n';
-  return headers_buf;
+always_inline void
+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);
+
+  /* name */
+  token = (http_custom_token_t *) (ctx->buf + ctx->tail_offset);
+  token->len = (u32) name_len;
+  clib_memcpy (token->token, (u8 *) name, token->len);
+  token->len |= HTTP_CUSTOM_HEADER_NAME_BIT;
+  ctx->tail_offset += sizeof (http_custom_token_t) + name_len;
+  /* value */
+  token = (http_custom_token_t *) (ctx->buf + ctx->tail_offset);
+  token->len = (u32) value_len;
+  clib_memcpy (token->token, (u8 *) value, token->len);
+  ctx->tail_offset += sizeof (http_custom_token_t) + value_len;
 }
 
 typedef enum http_uri_host_type_
index 55c5afc..995e55e 100644 (file)
@@ -16,10 +16,10 @@ Usage
 
 The plugin exposes following inline functions: ``http_validate_abs_path_syntax``, ``http_validate_query_syntax``,
 ``http_percent_decode``, ``http_path_remove_dot_segments``, ``http_build_header_table``, ``http_get_header``,
-``http_reset_header_table``, ``http_free_header_table``, ``http_add_header``, ``http_validate_target_syntax``,
-``http_serialize_headers``, ``http_parse_authority``, ``http_serialize_authority``, ``http_parse_masque_host_port``,
-``http_decap_udp_payload_datagram``, ``http_encap_udp_payload_datagram``. ``http_token_is``, ``http_token_is_case``,
-``http_token_contains``
+``http_reset_header_table``, ``http_free_header_table``, ``http_init_headers_ctx``, ``http_add_header``,
+``http_add_custom_header``, ``http_validate_target_syntax``, ``http_parse_authority``, ``http_serialize_authority``,
+``http_parse_masque_host_port``, ``http_decap_udp_payload_datagram``, ``http_encap_udp_payload_datagram``,
+``http_token_is``, ``http_token_is_case``, ``http_token_contains``
 
 It relies on the hoststack constructs and uses ``http_msg_data_t`` data structure for passing metadata to/from applications.
 
@@ -253,10 +253,9 @@ Application should set following items:
 * header section offset and length
 * body offset and length
 
-Application could pass headers back to HTTP layer. Header list is created dynamically as vector of ``http_header_t``,
-where we store only pointers to buffers (zero copy).
-Well known header names are predefined.
-The list is serialized just before you send buffer to HTTP layer.
+Application could pass headers back to HTTP layer. Header list is created dynamically using ``http_headers_ctx_t``, which must be initialized with preallocated buffer.
+Well known header names are predefined and are added using ``http_add_header``, for headers with custom names use ``http_add_custom_header``.
+Header list buffer is sent buffer to HTTP layer in raw, current length is stored ``tail_offset`` member of ``http_headers_ctx_t``.
 
 .. note::
     Following headers are added at protocol layer and **MUST NOT** be set by application: Date, Server, Content-Length, Connection, Upgrade
@@ -268,18 +267,20 @@ Following example shows how to create headers section:
   #include <http/http.h>
   #include <http/http_header_names.h>
   #include <http/http_content_types.h>
-  http_header_t *resp_headers = 0;
+  http_headers_ctx_t resp_headers;
   u8 *headers_buf = 0;
-  http_add_header (resp_headers,
-                  http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+  /* allocate buffer for response header list */
+  vec_validate (headers_buf, 1023);
+  /* initialize header list context */
+  http_init_headers_ctx (&resp_headers, headers_buf, vec_len (headers_buf));
+  /* add headers to the list */
+  http_add_header (&resp_headers, HTTP_HEADER_CONTENT_TYPE,
                   http_content_type_token (HTTP_CONTENT_TEXT_HTML));
-  http_add_header (resp_headers,
-                  http_header_name_token (HTTP_HEADER_CACHE_CONTROL),
+  http_add_header (&resp_headers, HTTP_HEADER_CACHE_CONTROL,
                   http_token_lit ("max-age=600"));
-  http_add_header (resp_headers,
-                  http_header_name_token (HTTP_HEADER_LOCATION),
-                  (const char *) redirect, vec_len (redirect));
-  headers_buf = http_serialize_headers (resp_headers);
+  http_add_custom_header (&resp_headers,
+                  http_token_lit ("X-Frame-Options"),
+                  (const char *) x_frame_opt, vec_len (x_frame_opt));
 
 The example below show how to create and send response HTTP message metadata:
 
@@ -289,7 +290,7 @@ The example below show how to create and send response HTTP message metadata:
   msg.type = HTTP_MSG_REPLY;
   msg.code = HTTP_STATUS_MOVED
   msg.data.headers_offset = 0;
-  msg.data.headers_len = vec_len (headers_buf);
+  msg.data.headers_len = resp_headers.tail_offset;
   msg.data.type = HTTP_MSG_DATA_INLINE;
   msg.data.body_len = vec_len (tx_buf);
   msg.data.body_offset = msg.data.headers_len;
@@ -298,11 +299,11 @@ The example below show how to create and send response HTTP message metadata:
   rv = svm_fifo_enqueue (ts->tx_fifo, sizeof (msg), (u8 *) &msg);
   ASSERT (rv == sizeof (msg));
 
-Next you will send your serialized headers:
+Next you will send your headers:
 
 .. code-block:: C
 
-  rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf);
+  rv = svm_fifo_enqueue (ts->tx_fifo, msg.data.headers_len, headers_buf);
   ASSERT (rv == msg.data.headers_len);
   vec_free (headers_buf);
 
@@ -377,13 +378,12 @@ The example below shows how to create headers section:
   #include <http/http.h>
   #include <http/http_header_names.h>
   #include <http/http_content_types.h>
-  http_header_t *req_headers = 0;
+  http_headers_ctx_t *req_headers;
   u8 *headers_buf = 0;
-  http_add_header (req_headers,
-                  http_header_name_token (HTTP_HEADER_ACCEPT),
+  vec_validate (headers_buf, 63);
+  http_init_headers_ctx (&eq_headers, headers_buf, vec_len (headers_buf));
+  http_add_header (req_headers, HTTP_HEADER_ACCEPT,
                   http_content_type_token (HTTP_CONTENT_TEXT_HTML));
-  headers_buf = http_serialize_headers (req_headers);
-  vec_free (hs->req_headers);
 
 Following example shows how to set message metadata:
 
@@ -398,7 +398,7 @@ Following example shows how to set message metadata:
   msg.data.target_path_len = vec_len (target);
   /* custom headers */
   msg.data.headers_offset = msg.data.target_path_len;
-  msg.data.headers_len = vec_len (headers_buf);
+  msg.data.headers_len = headers.tail_offset;
   /* no request body because we are doing GET request */
   msg.data.body_len = 0;
   /* data type and total length */
@@ -411,7 +411,7 @@ Finally application sends everything to HTTP layer:
 
   svm_fifo_seg_t segs[3] = { { (u8 *) &msg, sizeof (msg) }, /* message metadata */
                             { target, vec_len (target) }, /* request target */
-                            { headers_buf, vec_len (headers_buf) } }; /* serialized headers */
+                            { headers_buf, msg.data.headers_len } }; /* headers */
   rv = svm_fifo_enqueue_segments (as->tx_fifo, segs, 3, 0 /* allow partial */);
   vec_free (headers_buf);
   if (rv < 0 || rv != sizeof (msg) + msg.data.len)
index 5e0654f..88b0002 100644 (file)
@@ -53,9 +53,9 @@ typedef struct
   int free_data;
   /** File cache pool index */
   u32 cache_pool_index;
-  /** Response header list */
-  http_header_t *resp_headers;
-  /** Serialized headers to send */
+  /** Response header ctx */
+  http_headers_ctx_t resp_headers;
+  /** Response header buffer */
   u8 *headers_buf;
 } hss_session_t;
 
index fe5718b..7c8c65b 100644 (file)
@@ -19,7 +19,6 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#include <http/http_header_names.h>
 #include <http/http_content_types.h>
 
 /** @file static_server.c
@@ -41,6 +40,8 @@ hss_session_alloc (u32 thread_index)
   hs->session_index = hs - hsm->sessions[thread_index];
   hs->thread_index = thread_index;
   hs->cache_pool_index = ~0;
+  /* 1kB for headers should be enough for now */
+  vec_validate (hs->headers_buf, 1023);
   return hs;
 }
 
@@ -86,29 +87,17 @@ start_send_data (hss_session_t *hs, http_status_code_t status)
 {
   http_msg_t msg;
   session_t *ts;
-  u8 *headers_buf = 0;
   u32 n_enq;
   u64 to_send;
   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.data.body_len = hs->data_len;
+  msg.data.headers_offset = 0;
+  msg.data.headers_len = hs->resp_headers.tail_offset;
   msg.data.len = msg.data.body_len + msg.data.headers_len;
 
   if (msg.data.len > hss_main.use_ptr_thresh)
@@ -119,7 +108,6 @@ start_send_data (hss_session_t *hs, http_status_code_t status)
 
       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);
@@ -144,9 +132,9 @@ start_send_data (hss_session_t *hs, http_status_code_t status)
 
   if (msg.data.headers_len)
     {
-      rv = svm_fifo_enqueue (ts->tx_fifo, vec_len (headers_buf), headers_buf);
+      rv =
+       svm_fifo_enqueue (ts->tx_fifo, msg.data.headers_len, hs->headers_buf);
       ASSERT (rv == msg.data.headers_len);
-      vec_free (headers_buf);
     }
 
   if (!msg.data.body_len)
@@ -187,11 +175,8 @@ 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_name_token (HTTP_HEADER_CONTENT_TYPE),
-                      http_content_type_token (args->ct));
-    }
+    http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
+                    http_content_type_token (args->ct));
 
   start_send_data (hs, args->sc);
 }
@@ -320,11 +305,8 @@ 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_name_token (HTTP_HEADER_CONTENT_TYPE),
-                      http_content_type_token (args.ct));
-    }
+    http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
+                    http_content_type_token (args.ct));
 
   start_send_data (hs, sc);
 
@@ -401,10 +383,9 @@ 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_name_token (HTTP_HEADER_LOCATION),
+  http_add_header (&hs->resp_headers, HTTP_HEADER_LOCATION,
                   (const char *) redirect, vec_len (redirect));
-  hs->data = redirect; /* TODO: find better way  */
+  vec_free (redirect);
   hs->data_len = 0;
   hs->free_data = 1;
 
@@ -479,16 +460,15 @@ try_file_handler (hss_main_t *hsm, hss_session_t *hs, http_req_method_t rt,
   /* Set following headers only for happy path:
    * Content-Type
    * Cache-Control max-age
+   * Last-Modified
    */
   type = content_type_from_request (target);
-  http_add_header (&hs->resp_headers,
-                  http_header_name_token (HTTP_HEADER_CONTENT_TYPE),
+  http_add_header (&hs->resp_headers, HTTP_HEADER_CONTENT_TYPE,
                   http_content_type_token (type));
-  http_add_header (
-    &hs->resp_headers, http_header_name_token (HTTP_HEADER_CACHE_CONTROL),
-    (const char *) hsm->max_age_formatted, vec_len (hsm->max_age_formatted));
-  http_add_header (&hs->resp_headers,
-                  http_header_name_token (HTTP_HEADER_LAST_MODIFIED),
+  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));
 
 done:
@@ -529,8 +509,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);
+  http_init_headers_ctx (&hs->resp_headers, hs->headers_buf,
+                        vec_len (hs->headers_buf));
 
   /* Read the http message header */
   rv = svm_fifo_dequeue (ts->rx_fifo, sizeof (msg), (u8 *) &msg);
@@ -539,8 +519,7 @@ 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_add_header (&hs->resp_headers, HTTP_HEADER_ALLOW,
                       http_token_lit ("GET, POST"));
       start_send_data (hs, HTTP_STATUS_METHOD_NOT_ALLOWED);
       goto done;