From dbb38fffaef87c84960aa9f714a336056db3d9c9 Mon Sep 17 00:00:00 2001
From: Alexander Alashkin <alexander.alashkin@cesanta.com>
Date: Fri, 4 Mar 2016 09:36:40 +0000
Subject: [PATCH] Make (http) proto_data persistent

    PUBLISHED_FROM=8210f4730a3411b3298274d792fc33da79f47b8a
---
 mongoose.c | 889 ++++++++++++++++++++++++++++-------------------------
 mongoose.h |   8 +-
 2 files changed, 470 insertions(+), 427 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index eb02306d7..bc070da72 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -2147,6 +2147,9 @@ void mg_if_poll(struct mg_connection *nc, time_t now) {
 }
 
 static void mg_destroy_conn(struct mg_connection *conn) {
+  if (conn->proto_data != NULL && conn->proto_data_destructor != NULL) {
+    conn->proto_data_destructor(conn->proto_data);
+  }
   mg_if_destroy_conn(conn);
 #ifdef MG_ENABLE_SSL
   if (conn->ssl != NULL) SSL_free(conn->ssl);
@@ -2155,9 +2158,6 @@ static void mg_destroy_conn(struct mg_connection *conn) {
   mbuf_free(&conn->recv_mbuf);
   mbuf_free(&conn->send_mbuf);
   mbuf_free(&conn->endpoints);
-#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
-  mbuf_free(&conn->strm_state);
-#endif
 
   memset(conn, 0, sizeof(*conn));
   MG_FREE(conn);
@@ -2598,7 +2598,6 @@ struct mg_connection *mg_if_accept_new_conn(struct mg_connection *lc) {
   nc = mg_create_connection(lc->mgr, lc->handler, opts);
   if (nc == NULL) return NULL;
   nc->listener = lc;
-  nc->proto_data = lc->proto_data;
   nc->proto_handler = lc->proto_handler;
   nc->user_data = lc->user_data;
   nc->recv_mbuf_limit = lc->recv_mbuf_limit;
@@ -2686,7 +2685,6 @@ void mg_if_recv_udp_cb(struct mg_connection *nc, void *buf, int len,
       nc->sock = lc->sock;
       nc->listener = lc;
       nc->sa = *sa;
-      nc->proto_data = lc->proto_data;
       nc->proto_handler = lc->proto_handler;
       nc->user_data = lc->user_data;
       nc->recv_mbuf_limit = lc->recv_mbuf_limit;
@@ -4161,19 +4159,82 @@ int mg_normalize_uri_path(const struct mg_str *in, struct mg_str *out) {
 /* Amalgamated: #include "common/sha1.h" */
 /* Amalgamated: #include "common/md5.h" */
 
-enum http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT, DATA_CGI };
+enum mg_http_proto_data_type { DATA_NONE, DATA_FILE, DATA_PUT };
+
+struct mg_http_proto_data_file {
+  FILE *fp;     /* Opened file. */
+  int64_t cl;   /* Content-Length. How many bytes to send. */
+  int64_t sent; /* How many bytes have been already sent. */
+  enum mg_http_proto_data_type type;
+};
 
-struct proto_data_http {
+struct mg_http_proto_data_cgi {
+  struct mg_connection *cgi_nc;
+};
+
+struct mg_http_proto_data_chuncked {
+  int64_t body_len; /* How many bytes of chunked body was reassembled. */
+};
+
+struct mg_http_proto_data {
 #ifndef MG_DISABLE_FILESYSTEM
-  FILE *fp; /* Opened file. */
+  struct mg_http_proto_data_file file;
 #endif
-  int64_t cl;       /* Content-Length. How many bytes to send. */
-  int64_t sent;     /* How many bytes have been already sent. */
-  int64_t body_len; /* How many bytes of chunked body was reassembled. */
-  struct mg_connection *cgi_nc;
-  enum http_proto_data_type type;
+#ifndef MG_DISABLE_CGI
+  struct mg_http_proto_data_cgi cgi;
+#endif
+#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
+  struct mbuf strm_state; /* Used by multi-part streaming */
+#endif
+  struct mg_http_proto_data_chuncked chunk;
 };
 
+static void mg_http_conn_destructor(void *proto_data);
+
+static struct mg_http_proto_data *mg_http_get_proto_data(
+    struct mg_connection *c) {
+  if (c->proto_data == NULL) {
+    c->proto_data = MG_CALLOC(1, sizeof(struct mg_http_proto_data));
+    c->proto_data_destructor = mg_http_conn_destructor;
+  }
+
+  return (struct mg_http_proto_data *) c->proto_data;
+}
+
+#ifndef MG_DISABLE_FILESYSTEM
+static void mg_http_free_proto_data_file(struct mg_http_proto_data_file *d) {
+  if (d != NULL) {
+    if (d->fp != NULL) {
+      fclose(d->fp);
+    }
+    memset(d, 0, sizeof(struct mg_http_proto_data_file));
+  }
+}
+#endif
+
+#ifndef MG_DISABLE_CGI
+static void mg_http_free_proto_data_cgi(struct mg_http_proto_data_cgi *d) {
+  if (d != NULL) {
+    if (d->cgi_nc != NULL) d->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
+    memset(d, 0, sizeof(struct mg_http_proto_data_cgi));
+  }
+}
+#endif
+
+static void mg_http_conn_destructor(void *proto_data) {
+  struct mg_http_proto_data *pd = (struct mg_http_proto_data *) proto_data;
+#ifndef MG_DISABLE_FILESYSTEM
+  mg_http_free_proto_data_file(&pd->file);
+#endif
+#ifndef MG_DISABLE_CGI
+  mg_http_free_proto_data_cgi(&pd->cgi);
+#endif
+#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
+  mbuf_free(&pd->strm_state);
+#endif
+  free(proto_data);
+}
+
 /*
  * This structure helps to create an environment for the spawned CGI program.
  * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
@@ -4184,7 +4245,7 @@ struct proto_data_http {
  * We satisfy both worlds: we create an envp array (which is vars), all
  * entries are actually pointers inside buf.
  */
-struct cgi_env_block {
+struct mg_cgi_env_block {
   struct mg_connection *nc;
   char buf[MG_CGI_ENVIRONMENT_SIZE];       /* Environment buffer */
   const char *vars[MG_MAX_CGI_ENVIR_VARS]; /* char *envp[] */
@@ -4198,7 +4259,7 @@ static const struct {
   const char *extension;
   size_t ext_len;
   const char *mime_type;
-} static_builtin_mime_types[] = {
+} mg_static_builtin_mime_types[] = {
     MIME_ENTRY("html", "text/html"),
     MIME_ENTRY("html", "text/html"),
     MIME_ENTRY("htm", "text/html"),
@@ -4262,8 +4323,8 @@ static int mg_mkdir(const char *path, uint32_t mode) {
 }
 #endif
 
-static struct mg_str get_mime_type(const char *path, const char *dflt,
-                                   const struct mg_serve_http_opts *opts) {
+static struct mg_str mg_get_mime_type(const char *path, const char *dflt,
+                                      const struct mg_serve_http_opts *opts) {
   const char *ext, *overrides;
   size_t i, path_len;
   struct mg_str r, k, v;
@@ -4278,11 +4339,11 @@ static struct mg_str get_mime_type(const char *path, const char *dflt,
     }
   }
 
-  for (i = 0; static_builtin_mime_types[i].extension != NULL; i++) {
-    ext = path + (path_len - static_builtin_mime_types[i].ext_len);
-    if (path_len > static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
-        mg_casecmp(ext, static_builtin_mime_types[i].extension) == 0) {
-      r.p = static_builtin_mime_types[i].mime_type;
+  for (i = 0; mg_static_builtin_mime_types[i].extension != NULL; i++) {
+    ext = path + (path_len - mg_static_builtin_mime_types[i].ext_len);
+    if (path_len > mg_static_builtin_mime_types[i].ext_len && ext[-1] == '.' &&
+        mg_casecmp(ext, mg_static_builtin_mime_types[i].extension) == 0) {
+      r.p = mg_static_builtin_mime_types[i].mime_type;
       r.len = strlen(r.p);
       return r;
     }
@@ -4300,7 +4361,7 @@ static struct mg_str get_mime_type(const char *path, const char *dflt,
  *    0  if request is not yet fully buffered
  *   >0  actual request length, including last \r\n\r\n
  */
-static int get_request_len(const char *s, int buf_len) {
+static int mg_http_get_request_len(const char *s, int buf_len) {
   const unsigned char *buf = (unsigned char *) s;
   int i;
 
@@ -4318,8 +4379,8 @@ static int get_request_len(const char *s, int buf_len) {
   return 0;
 }
 
-static const char *parse_http_headers(const char *s, const char *end, int len,
-                                      struct http_message *req) {
+static const char *mg_http_parse_headers(const char *s, const char *end,
+                                         int len, struct http_message *req) {
   int i;
   for (i = 0; i < (int) ARRAY_SIZE(req->header_names) - 1; i++) {
     struct mg_str *k = &req->header_names[i], *v = &req->header_values[i];
@@ -4348,7 +4409,7 @@ static const char *parse_http_headers(const char *s, const char *end, int len,
 
 int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
   const char *end, *qs;
-  int len = get_request_len(s, n);
+  int len = mg_http_get_request_len(s, n);
 
   if (len <= 0) return len;
 
@@ -4383,7 +4444,7 @@ int mg_parse_http(const char *s, int n, struct http_message *hm, int is_req) {
     s = mg_skip(s, end, "\r\n", &hm->resp_status_msg);
   }
 
-  s = parse_http_headers(s, end, len, hm);
+  s = mg_http_parse_headers(s, end, len, hm);
 
   /*
    * mg_parse_http() is used to parse both HTTP requests and HTTP
@@ -4424,16 +4485,16 @@ struct mg_str *mg_get_http_header(struct http_message *hm, const char *name) {
 
 #ifndef MG_DISABLE_HTTP_WEBSOCKET
 
-static int is_ws_fragment(unsigned char flags) {
+static int mg_is_ws_fragment(unsigned char flags) {
   return (flags & 0x80) == 0 || (flags & 0x0f) == 0;
 }
 
-static int is_ws_first_fragment(unsigned char flags) {
+static int mg_is_ws_first_fragment(unsigned char flags) {
   return (flags & 0x80) == 0 && (flags & 0x0f) != 0;
 }
 
-static void handle_incoming_websocket_frame(struct mg_connection *nc,
-                                            struct websocket_message *wsm) {
+static void mg_handle_incoming_websocket_frame(struct mg_connection *nc,
+                                               struct websocket_message *wsm) {
   if (wsm->flags & 0x8) {
     mg_call(nc, nc->handler, MG_EV_WEBSOCKET_CONTROL_FRAME, wsm);
   } else {
@@ -4441,19 +4502,19 @@ static void handle_incoming_websocket_frame(struct mg_connection *nc,
   }
 }
 
-static int deliver_websocket_data(struct mg_connection *nc) {
+static int mg_deliver_websocket_data(struct mg_connection *nc) {
   /* Using unsigned char *, cause of integer arithmetic below */
   uint64_t i, data_len = 0, frame_len = 0, buf_len = nc->recv_mbuf.len, len,
               mask_len = 0, header_len = 0;
   unsigned char *p = (unsigned char *) nc->recv_mbuf.buf, *buf = p,
                 *e = p + buf_len;
   unsigned *sizep = (unsigned *) &p[1]; /* Size ptr for defragmented frames */
-  int ok, reass = buf_len > 0 && is_ws_fragment(p[0]) &&
+  int ok, reass = buf_len > 0 && mg_is_ws_fragment(p[0]) &&
                   !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG);
 
   /* If that's a continuation frame that must be reassembled, handle it */
-  if (reass && !is_ws_first_fragment(p[0]) && buf_len >= 1 + sizeof(*sizep) &&
-      buf_len >= 1 + sizeof(*sizep) + *sizep) {
+  if (reass && !mg_is_ws_first_fragment(p[0]) &&
+      buf_len >= 1 + sizeof(*sizep) && buf_len >= 1 + sizeof(*sizep) + *sizep) {
     buf += 1 + sizeof(*sizep) + *sizep;
     buf_len -= 1 + sizeof(*sizep) + *sizep;
   }
@@ -4493,7 +4554,7 @@ static int deliver_websocket_data(struct mg_connection *nc) {
 
     if (reass) {
       /* On first fragmented frame, nullify size */
-      if (is_ws_first_fragment(wsm.flags)) {
+      if (mg_is_ws_first_fragment(wsm.flags)) {
         mbuf_resize(&nc->recv_mbuf, nc->recv_mbuf.size + sizeof(*sizep));
         p[0] &= ~0x0f; /* Next frames will be treated as continuation */
         buf = p + 1 + sizeof(*sizep);
@@ -4509,12 +4570,12 @@ static int deliver_websocket_data(struct mg_connection *nc) {
       if (wsm.flags & 0x80) {
         wsm.data = p + 1 + sizeof(*sizep);
         wsm.size = *sizep;
-        handle_incoming_websocket_frame(nc, &wsm);
+        mg_handle_incoming_websocket_frame(nc, &wsm);
         mbuf_remove(&nc->recv_mbuf, 1 + sizeof(*sizep) + *sizep);
       }
     } else {
       /* TODO(lsm): properly handle OOB control frames during defragmentation */
-      handle_incoming_websocket_frame(nc, &wsm);
+      mg_handle_incoming_websocket_frame(nc, &wsm);
       mbuf_remove(&nc->recv_mbuf, (size_t) frame_len); /* Cleanup frame */
     }
 
@@ -4532,7 +4593,7 @@ struct ws_mask_ctx {
   uint32_t mask;
 };
 
-static uint32_t ws_random_mask(void) {
+static uint32_t mg_ws_random_mask(void) {
 /*
  * The spec requires WS client to generate hard to
  * guess mask keys. From RFC6455, Section 5.3:
@@ -4586,7 +4647,7 @@ static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
   if (nc->listener == NULL) {
     header[1] |= 1 << 7; /* set masking flag */
     mg_send(nc, header, header_len);
-    ctx->mask = ws_random_mask();
+    ctx->mask = mg_ws_random_mask();
     mg_send(nc, &ctx->mask, sizeof(ctx->mask));
     ctx->pos = nc->send_mbuf.len;
   } else {
@@ -4595,7 +4656,7 @@ static void mg_send_ws_header(struct mg_connection *nc, int op, size_t len,
   }
 }
 
-static void ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
+static void mg_ws_mask_frame(struct mbuf *mbuf, struct ws_mask_ctx *ctx) {
   size_t i;
   if (ctx->pos == 0) return;
   for (i = 0; i < (mbuf->len - ctx->pos); i++) {
@@ -4609,7 +4670,7 @@ void mg_send_websocket_frame(struct mg_connection *nc, int op, const void *data,
   mg_send_ws_header(nc, op, len, &ctx);
   mg_send(nc, data, len);
 
-  ws_mask_frame(&nc->send_mbuf, &ctx);
+  mg_ws_mask_frame(&nc->send_mbuf, &ctx);
 
   if (op == WEBSOCKET_OP_CLOSE) {
     nc->flags |= MG_F_SEND_AND_CLOSE;
@@ -4631,7 +4692,7 @@ void mg_send_websocket_framev(struct mg_connection *nc, int op,
     mg_send(nc, strv[i].p, strv[i].len);
   }
 
-  ws_mask_frame(&nc->send_mbuf, &ctx);
+  mg_ws_mask_frame(&nc->send_mbuf, &ctx);
 
   if (op == WEBSOCKET_OP_CLOSE) {
     nc->flags |= MG_F_SEND_AND_CLOSE;
@@ -4655,13 +4716,14 @@ void mg_printf_websocket_frame(struct mg_connection *nc, int op,
   }
 }
 
-static void websocket_handler(struct mg_connection *nc, int ev, void *ev_data) {
+static void mg_websocket_handler(struct mg_connection *nc, int ev,
+                                 void *ev_data) {
   mg_call(nc, nc->handler, ev, ev_data);
 
   switch (ev) {
     case MG_EV_RECV:
       do {
-      } while (deliver_websocket_data(nc));
+      } while (mg_deliver_websocket_data(nc));
       break;
     case MG_EV_POLL:
       /* Ping idle websocket connections */
@@ -4678,7 +4740,8 @@ static void websocket_handler(struct mg_connection *nc, int ev, void *ev_data) {
   }
 }
 
-static void ws_handshake(struct mg_connection *nc, const struct mg_str *key) {
+static void mg_ws_handshake(struct mg_connection *nc,
+                            const struct mg_str *key) {
   static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
   char buf[MG_VPRINTF_BUFFER_SIZE], sha[20], b64_sha[sizeof(sha) * 2];
   cs_sha1_ctx sha_ctx;
@@ -4700,28 +4763,14 @@ static void ws_handshake(struct mg_connection *nc, const struct mg_str *key) {
 
 #endif /* MG_DISABLE_HTTP_WEBSOCKET */
 
-static void free_http_proto_data(struct mg_connection *nc) {
-  struct proto_data_http *dp = (struct proto_data_http *) nc->proto_data;
-  if (dp != NULL) {
 #ifndef MG_DISABLE_FILESYSTEM
-    if (dp->fp != NULL) fclose(dp->fp);
-#endif
-#ifndef MG_DISABLE_CGI
-    if (dp->cgi_nc != NULL) dp->cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
-#endif
-    MG_FREE(dp);
-    nc->proto_data = NULL;
-  }
-}
-
-#ifndef MG_DISABLE_FILESYSTEM
-static void transfer_file_data(struct mg_connection *nc) {
-  struct proto_data_http *dp = (struct proto_data_http *) nc->proto_data;
+static void mg_http_transfer_file_data(struct mg_connection *nc) {
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   char buf[MG_MAX_HTTP_SEND_MBUF];
-  int64_t left = dp->cl - dp->sent;
+  int64_t left = pd->file.cl - pd->file.sent;
   size_t n = 0, to_read = 0;
 
-  if (dp->type == DATA_FILE) {
+  if (pd->file.type == DATA_FILE) {
     struct mbuf *io = &nc->send_mbuf;
     if (io->len < sizeof(buf)) {
       to_read = sizeof(buf) - io->len;
@@ -4733,38 +4782,42 @@ static void transfer_file_data(struct mg_connection *nc) {
 
     if (to_read == 0) {
       /* Rate limiting. send_mbuf is too full, wait until it's drained. */
-    } else if (dp->sent < dp->cl && (n = fread(buf, 1, to_read, dp->fp)) > 0) {
+    } else if (pd->file.sent < pd->file.cl &&
+               (n = fread(buf, 1, to_read, pd->file.fp)) > 0) {
       mg_send(nc, buf, n);
-      dp->sent += n;
+      pd->file.sent += n;
     } else {
-      free_http_proto_data(nc);
+      mg_http_free_proto_data_file(&pd->file);
 #ifdef MG_DISABLE_HTTP_KEEP_ALIVE
       nc->flags |= MG_F_SEND_AND_CLOSE;
 #endif
     }
-  } else if (dp->type == DATA_PUT) {
+  } else if (pd->file.type == DATA_PUT) {
     struct mbuf *io = &nc->recv_mbuf;
     size_t to_write =
         left <= 0 ? 0 : left < (int64_t) io->len ? (size_t) left : io->len;
-    size_t n = fwrite(io->buf, 1, to_write, dp->fp);
+    size_t n = fwrite(io->buf, 1, to_write, pd->file.fp);
     if (n > 0) {
       mbuf_remove(io, n);
-      dp->sent += n;
+      pd->file.sent += n;
     }
-    if (n == 0 || dp->sent >= dp->cl) {
-      free_http_proto_data(nc);
+    if (n == 0 || pd->file.sent >= pd->file.cl) {
+      mg_http_free_proto_data_file(&pd->file);
 #ifdef MG_DISABLE_HTTP_KEEP_ALIVE
       nc->flags |= MG_F_SEND_AND_CLOSE;
 #endif
     }
-  } else if (dp->type == DATA_CGI) {
+  }
+#ifndef MG_DISABLE_CGI
+  else if (pd->cgi.cgi_nc != NULL) {
     /* This is POST data that needs to be forwarded to the CGI process */
-    if (dp->cgi_nc != NULL) {
-      mg_forward(nc, dp->cgi_nc);
+    if (pd->cgi.cgi_nc != NULL) {
+      mg_forward(nc, pd->cgi.cgi_nc);
     } else {
       nc->flags |= MG_F_SEND_AND_CLOSE;
     }
   }
+#endif
 }
 #endif /* MG_DISABLE_FILESYSTEM */
 
@@ -4773,8 +4826,8 @@ static void transfer_file_data(struct mg_connection *nc) {
  * if it's incomplete. If the chunk is fully buffered, return total number of
  * bytes in a chunk, and store data in `data`, `data_len`.
  */
-static size_t parse_chunk(char *buf, size_t len, char **chunk_data,
-                          size_t *chunk_len) {
+static size_t mg_http_parse_chunk(char *buf, size_t len, char **chunk_data,
+                                  size_t *chunk_len) {
   unsigned char *s = (unsigned char *) buf;
   size_t n = 0; /* scanned chunk length */
   size_t i = 0; /* index in s */
@@ -4809,24 +4862,17 @@ static size_t parse_chunk(char *buf, size_t len, char **chunk_data,
 MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
                                      struct http_message *hm, char *buf,
                                      size_t blen) {
-  struct proto_data_http *dp;
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   char *data;
   size_t i, n, data_len, body_len, zero_chunk_received = 0;
 
-  /* If not allocated, allocate proto_data to hold reassembled offset */
-  if (nc->proto_data == NULL &&
-      (nc->proto_data = MG_CALLOC(1, sizeof(*dp))) == NULL) {
-    nc->flags |= MG_F_CLOSE_IMMEDIATELY;
-    return 0;
-  }
-
   /* Find out piece of received data that is not yet reassembled */
-  dp = (struct proto_data_http *) nc->proto_data;
-  body_len = dp->body_len;
+  body_len = pd->chunk.body_len;
   assert(blen >= body_len);
 
   /* Traverse all fully buffered chunks */
-  for (i = body_len; (n = parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
+  for (i = body_len;
+       (n = mg_http_parse_chunk(buf + i, blen - i, &data, &data_len)) > 0;
        i += n) {
     /* Collapse chunk data to the rest of HTTP body */
     memmove(buf + body_len, data, data_len);
@@ -4846,7 +4892,7 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
     memmove(buf + body_len, buf + i, blen - i);
     memset(buf + body_len + blen - i, 0, i - body_len);
     nc->recv_mbuf.len -= i - body_len;
-    dp->body_len = body_len;
+    pd->chunk.body_len = body_len;
 
     /* Send MG_EV_HTTP_CHUNK event */
     nc->flags &= ~MG_F_DELETE_CHUNK;
@@ -4857,19 +4903,19 @@ MG_INTERNAL size_t mg_handle_chunked(struct mg_connection *nc,
       memset(buf, 0, body_len);
       memmove(buf, buf + body_len, blen - i);
       nc->recv_mbuf.len -= body_len;
-      hm->body.len = dp->body_len = 0;
+      hm->body.len = pd->chunk.body_len = 0;
     }
 
     if (zero_chunk_received) {
-      hm->message.len = dp->body_len + blen - i;
+      hm->message.len = pd->chunk.body_len + blen - i;
     }
   }
 
   return body_len;
 }
 
-static mg_event_handler_t get_endpoint_handler(struct mg_connection *nc,
-                                               struct mg_str *uri_path) {
+static mg_event_handler_t mg_http_get_endpoint_handler(
+    struct mg_connection *nc, struct mg_str *uri_path) {
   size_t pos = 0;
   mg_event_handler_t ret = NULL;
   int matched, matched_max = 0;
@@ -4900,7 +4946,7 @@ static mg_event_handler_t get_endpoint_handler(struct mg_connection *nc,
 }
 
 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
-struct stream_info {
+struct mg_http_stream_info {
   struct mg_str endpoint;
   struct mg_str boundary;
   struct mg_str var_name;
@@ -4914,7 +4960,8 @@ struct stream_info {
  * related data these function can be replaced with usual structs
  * TODO(alashkin): replace once those way will be implemented
  */
-static void mg_parse_stream_info(struct mbuf *buf, struct stream_info *si) {
+static void mg_http_parse_stream_info(struct mbuf *buf,
+                                      struct mg_http_stream_info *si) {
   const char *ptr = buf->buf;
   memcpy(&si->endpoint.len, ptr, sizeof(si->endpoint.len));
   ptr += sizeof(si->endpoint.len);
@@ -4934,7 +4981,8 @@ static void mg_parse_stream_info(struct mbuf *buf, struct stream_info *si) {
   ptr += si->file_name.len + 1;
 }
 
-static void mg_store_stream_info(struct mbuf *buf, struct stream_info *si) {
+static void mg_http_store_stream_info(struct mbuf *buf,
+                                      struct mg_http_stream_info *si) {
   char zero = 0;
   mbuf_remove(buf, buf->len);
   mbuf_append(buf, &si->endpoint.len, sizeof(si->endpoint.len));
@@ -4951,21 +4999,22 @@ static void mg_store_stream_info(struct mbuf *buf, struct stream_info *si) {
 }
 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
 
-static void mg_call_endpoint_handler(struct mg_connection *nc, int ev,
-                                     struct http_message *hm) {
+static void mg_http_call_endpoint_handler(struct mg_connection *nc, int ev,
+                                          struct http_message *hm) {
   mg_event_handler_t uri_handler =
-      ev == MG_EV_HTTP_REQUEST ? get_endpoint_handler(nc->listener, &hm->uri)
-                               : NULL;
+      ev == MG_EV_HTTP_REQUEST
+          ? mg_http_get_endpoint_handler(nc->listener, &hm->uri)
+          : NULL;
   mg_call(nc, uri_handler ? uri_handler : nc->handler, ev, hm);
 }
 
 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
-static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
-                                  int ev, void *ev_data);
+static void mg_http_multipart_continue(struct mg_connection *nc,
+                                       struct mbuf *io, int ev, void *ev_data);
 
-static void mg_multipart_begin(struct mg_connection *nc,
-                               struct http_message *hm, struct mbuf *io,
-                               int req_len);
+static void mg_http_multipart_begin(struct mg_connection *nc,
+                                    struct http_message *hm, struct mbuf *io,
+                                    int req_len);
 
 #endif
 
@@ -4975,21 +5024,22 @@ static void mg_multipart_begin(struct mg_connection *nc,
  * even bigger (round up to 4k, from 700 bytes of actual size).
  */
 #ifdef __xtensa__
-static void http_handler2(struct mg_connection *nc, int ev, void *ev_data,
-                          struct http_message *hm) __attribute__((noinline));
+static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data,
+                             struct http_message *hm) __attribute__((noinline));
 
-void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
+void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) {
   struct http_message hm;
-  http_handler2(nc, ev, ev_data, &hm);
+  mg_http_handler2(nc, ev, ev_data, &hm);
 }
 
-static void http_handler2(struct mg_connection *nc, int ev, void *ev_data,
-                          struct http_message *hm) {
+static void mg_http_handler2(struct mg_connection *nc, int ev, void *ev_data,
+                             struct http_message *hm) {
 #else  /* !__XTENSA__ */
-void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
+void mg_http_handler(struct mg_connection *nc, int ev, void *ev_data) {
   struct http_message shm;
   struct http_message *hm = &shm;
 #endif /* __XTENSA__ */
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   struct mbuf *io = &nc->recv_mbuf;
   int req_len;
   const int is_req = (nc->listener != NULL);
@@ -5005,14 +5055,13 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
       int ev2 = is_req ? MG_EV_HTTP_REQUEST : MG_EV_HTTP_REPLY;
       hm->message.len = io->len;
       hm->body.len = io->buf + io->len - hm->body.p;
-      mg_call_endpoint_handler(nc, ev2, hm);
+      mg_http_call_endpoint_handler(nc, ev2, hm);
     }
-    free_http_proto_data(nc);
   }
 
 #ifndef MG_DISABLE_FILESYSTEM
-  if (nc->proto_data != NULL) {
-    transfer_file_data(nc);
+  if (pd->file.fp != NULL) {
+    mg_http_transfer_file_data(nc);
   }
 #endif
 
@@ -5022,8 +5071,8 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
     struct mg_str *s;
 
 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
-    if (nc->strm_state.len != 0) {
-      mg_multipart_continue(nc, io, ev, ev_data);
+    if (pd->strm_state.len != 0) {
+      mg_http_multipart_continue(nc, io, ev, ev_data);
       return;
     }
 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
@@ -5050,25 +5099,25 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
       /* We're websocket client, got handshake response from server. */
       /* TODO(lsm): check the validity of accept Sec-WebSocket-Accept */
       mbuf_remove(io, req_len);
-      nc->proto_handler = websocket_handler;
+      nc->proto_handler = mg_websocket_handler;
       nc->flags |= MG_F_IS_WEBSOCKET;
       mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL);
-      websocket_handler(nc, MG_EV_RECV, ev_data);
+      mg_websocket_handler(nc, MG_EV_RECV, ev_data);
     } else if (nc->listener != NULL &&
                (vec = mg_get_http_header(hm, "Sec-WebSocket-Key")) != NULL) {
       /* This is a websocket request. Switch protocol handlers. */
       mbuf_remove(io, req_len);
-      nc->proto_handler = websocket_handler;
+      nc->proto_handler = mg_websocket_handler;
       nc->flags |= MG_F_IS_WEBSOCKET;
 
       /* Send handshake */
       mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_REQUEST, hm);
       if (!(nc->flags & MG_F_CLOSE_IMMEDIATELY)) {
         if (nc->send_mbuf.len == 0) {
-          ws_handshake(nc, vec);
+          mg_ws_handshake(nc, vec);
         }
         mg_call(nc, nc->handler, MG_EV_WEBSOCKET_HANDSHAKE_DONE, NULL);
-        websocket_handler(nc, MG_EV_RECV, ev_data);
+        mg_websocket_handler(nc, MG_EV_RECV, ev_data);
       }
 #endif /* MG_DISABLE_HTTP_WEBSOCKET */
     } else if (hm->message.len <= io->len) {
@@ -5119,29 +5168,30 @@ void http_handler(struct mg_connection *nc, int ev, void *ev_data) {
       if (js_callback_handled_request) {
         nc->flags |= MG_F_SEND_AND_CLOSE;
       } else {
-        mg_call_endpoint_handler(nc, trigger_ev, hm);
+        mg_http_call_endpoint_handler(nc, trigger_ev, hm);
       }
 #else
-    mg_call_endpoint_handler(nc, trigger_ev, hm);
+    mg_http_call_endpoint_handler(nc, trigger_ev, hm);
 #endif
       mbuf_remove(io, hm->message.len);
 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
     } else {
-      mg_multipart_begin(nc, hm, io, req_len);
+      mg_http_multipart_begin(nc, hm, io, req_len);
 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
     }
   }
 }
 
 #ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
-static void mg_multipart_begin(struct mg_connection *nc,
-                               struct http_message *hm, struct mbuf *io,
-                               int req_len) {
+static void mg_http_multipart_begin(struct mg_connection *nc,
+                                    struct http_message *hm, struct mbuf *io,
+                                    int req_len) {
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   struct mg_str *ct;
   const char multipart[] = "multipart";
   char boundary[100];
   int boundary_len;
-  struct stream_info si;
+  struct mg_http_stream_info si;
   mg_event_handler_t handler;
 
   if (nc->listener == NULL) {
@@ -5176,13 +5226,13 @@ static void mg_multipart_begin(struct mg_connection *nc,
 
   /* If we reach this place - that is multipart request */
 
-  if (nc->strm_state.len != 0) {
+  if (pd->strm_state.len != 0) {
     /*
      * Another streaming request was in progress,
      * looks like protocol error
      */
     nc->flags |= MG_F_CLOSE_IMMEDIATELY;
-    mbuf_free(&nc->strm_state);
+    mbuf_free(&pd->strm_state);
   } else {
     si.endpoint = hm->uri;
     si.boundary.p = boundary;
@@ -5190,8 +5240,8 @@ static void mg_multipart_begin(struct mg_connection *nc,
     si.var_name.p = si.file_name.p = NULL;
     si.var_name.len = si.file_name.len = 0;
 
-    mg_store_stream_info(&nc->strm_state, &si);
-    handler = get_endpoint_handler(nc->listener, &si.endpoint);
+    mg_http_store_stream_info(&pd->strm_state, &si);
+    handler = mg_http_get_endpoint_handler(nc->listener, &si.endpoint);
     mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_MULTIPART_REQUEST,
             hm);
 
@@ -5201,17 +5251,18 @@ exit_mp:
   ;
 }
 
-static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
-                                  int ev, void *ev_data) {
+static void mg_http_multipart_continue(struct mg_connection *nc,
+                                       struct mbuf *io, int ev, void *ev_data) {
   /* Continue to stream multipart */
-  struct stream_info si;
+  struct mg_http_stream_info si;
   mg_event_handler_t handler;
   struct mg_http_multipart_part mp;
   const char *boundary;
   int req_len;
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
 
-  mg_parse_stream_info(&nc->strm_state, &si);
-  handler = get_endpoint_handler(nc->listener, &si.endpoint);
+  mg_http_parse_stream_info(&pd->strm_state, &si);
+  handler = mg_http_get_endpoint_handler(nc->listener, &si.endpoint);
   memset(&mp, 0, sizeof(mp));
 
   mp.var_name = si.var_name.p;
@@ -5250,7 +5301,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
                          sizeof(filename), &data, &data_len);
       mp.var_name = varname;
       mp.file_name = filename;
-      if ((req_len = get_request_len(io->buf, io->len)) > 0) {
+      if ((req_len = mg_http_get_request_len(io->buf, io->len)) > 0) {
         const char *tmp;
         mg_call(nc, handler ? handler : nc->handler, MG_EV_HTTP_PART_BEGIN,
                 &mp);
@@ -5258,7 +5309,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
         si.var_name.len = strlen(mp.var_name);
         si.file_name.p = mp.file_name;
         si.file_name.len = strlen(mp.file_name);
-        mg_store_stream_info(&nc->strm_state, &si);
+        mg_http_store_stream_info(&pd->strm_state, &si);
 
         mbuf_remove(io, req_len);
         mp.data.p = io->buf;
@@ -5283,7 +5334,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
         }
 
         if (io->len != 0) {
-          http_handler(nc, ev, ev_data);
+          mg_http_handler(nc, ev, ev_data);
         }
       } /* else wait for data */
     } else if (has_prefix && has_suffix) {
@@ -5298,7 +5349,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
 
       /* Skip epilogue (if any) */
       mbuf_remove(io, io->len);
-      mbuf_free(&nc->strm_state);
+      mbuf_free(&pd->strm_state);
     } else {
       /* Malformed request */
       nc->flags |= MG_F_CLOSE_IMMEDIATELY;
@@ -5309,7 +5360,7 @@ static void mg_multipart_continue(struct mg_connection *nc, struct mbuf *io,
 #endif /* MG_ENABLE_HTTP_STREAMING_MULTIPART */
 
 void mg_set_protocol_http_websocket(struct mg_connection *nc) {
-  nc->proto_handler = http_handler;
+  nc->proto_handler = mg_http_handler;
 }
 
 #ifndef MG_DISABLE_HTTP_WEBSOCKET
@@ -5384,16 +5435,16 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
   mg_send_head(nc, 501, 0, NULL);
 }
 #else
-static void send_http_error(struct mg_connection *nc, int code,
-                            const char *reason) {
+static void mg_http_send_http_error(struct mg_connection *nc, int code,
+                                    const char *reason) {
   (void) reason;
   mg_send_head(nc, code, 0, NULL);
 }
 #ifndef MG_DISABLE_SSI
-static void send_ssi_file(struct mg_connection *, const char *, FILE *, int,
-                          const struct mg_serve_http_opts *);
+static void mg_send_ssi_file(struct mg_connection *, const char *, FILE *, int,
+                             const struct mg_serve_http_opts *);
 
-static void send_file_data(struct mg_connection *nc, FILE *fp) {
+static void mg_send_file_data(struct mg_connection *nc, FILE *fp) {
   char buf[BUFSIZ];
   size_t n;
   while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) {
@@ -5401,9 +5452,9 @@ static void send_file_data(struct mg_connection *nc, FILE *fp) {
   }
 }
 
-static void do_ssi_include(struct mg_connection *nc, const char *ssi, char *tag,
-                           int include_level,
-                           const struct mg_serve_http_opts *opts) {
+static void mg_do_ssi_include(struct mg_connection *nc, const char *ssi,
+                              char *tag, int include_level,
+                              const struct mg_serve_http_opts *opts) {
   char file_name[BUFSIZ], path[MAX_PATH_SIZE], *p;
   FILE *fp;
 
@@ -5439,9 +5490,9 @@ static void do_ssi_include(struct mg_connection *nc, const char *ssi, char *tag,
     mg_set_close_on_exec(fileno(fp));
     if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern), path) >
         0) {
-      send_ssi_file(nc, path, fp, include_level + 1, opts);
+      mg_send_ssi_file(nc, path, fp, include_level + 1, opts);
     } else {
-      send_file_data(nc, fp);
+      mg_send_file_data(nc, fp);
     }
     fclose(fp);
   }
@@ -5457,13 +5508,13 @@ static void do_ssi_exec(struct mg_connection *nc, char *tag) {
   } else if ((fp = popen(cmd, "r")) == NULL) {
     mg_printf(nc, "Cannot SSI #exec: [%s]: %s", cmd, strerror(errno));
   } else {
-    send_file_data(nc, fp);
+    mg_send_file_data(nc, fp);
     pclose(fp);
   }
 }
 #endif /* !MG_DISABLE_POPEN */
 
-static void do_ssi_call(struct mg_connection *nc, char *tag) {
+static void mg_do_ssi_call(struct mg_connection *nc, char *tag) {
   mg_call(nc, NULL, MG_EV_SSI_CALL, tag);
 }
 
@@ -5471,9 +5522,9 @@ static void do_ssi_call(struct mg_connection *nc, char *tag) {
  * SSI directive has the following format:
  * <!--#directive parameter=value parameter=value -->
  */
-static void send_ssi_file(struct mg_connection *nc, const char *path, FILE *fp,
-                          int include_level,
-                          const struct mg_serve_http_opts *opts) {
+static void mg_send_ssi_file(struct mg_connection *nc, const char *path,
+                             FILE *fp, int include_level,
+                             const struct mg_serve_http_opts *opts) {
   static const struct mg_str btag = MG_MK_STR("<!--#");
   static const struct mg_str d_include = MG_MK_STR("include");
   static const struct mg_str d_call = MG_MK_STR("call");
@@ -5502,9 +5553,9 @@ static void send_ssi_file(struct mg_connection *nc, const char *path, FILE *fp,
 
       /* Handle known SSI directives */
       if (memcmp(p, d_include.p, d_include.len) == 0) {
-        do_ssi_include(nc, path, p + d_include.len + 1, include_level, opts);
+        mg_do_ssi_include(nc, path, p + d_include.len + 1, include_level, opts);
       } else if (memcmp(p, d_call.p, d_call.len) == 0) {
-        do_ssi_call(nc, p + d_call.len + 1);
+        mg_do_ssi_call(nc, p + d_call.len + 1);
 #ifndef MG_DISABLE_POPEN
       } else if (memcmp(p, d_exec.p, d_exec.len) == 0) {
         do_ssi_exec(nc, p + d_exec.len + 1);
@@ -5544,46 +5595,47 @@ static void send_ssi_file(struct mg_connection *nc, const char *path, FILE *fp,
   }
 }
 
-static void handle_ssi_request(struct mg_connection *nc, const char *path,
-                               const struct mg_serve_http_opts *opts) {
+static void mg_handle_ssi_request(struct mg_connection *nc, const char *path,
+                                  const struct mg_serve_http_opts *opts) {
   FILE *fp;
   struct mg_str mime_type;
 
   if ((fp = fopen(path, "rb")) == NULL) {
-    send_http_error(nc, 404, NULL);
+    mg_http_send_http_error(nc, 404, NULL);
   } else {
     mg_set_close_on_exec(fileno(fp));
 
-    mime_type = get_mime_type(path, "text/plain", opts);
+    mime_type = mg_get_mime_type(path, "text/plain", opts);
     mg_send_response_line(nc, 200, opts->extra_headers);
     mg_printf(nc,
               "Content-Type: %.*s\r\n"
               "Connection: close\r\n\r\n",
               (int) mime_type.len, mime_type.p);
-    send_ssi_file(nc, path, fp, 0, opts);
+    mg_send_ssi_file(nc, path, fp, 0, opts);
     fclose(fp);
     nc->flags |= MG_F_SEND_AND_CLOSE;
   }
 }
 #else
-static void handle_ssi_request(struct mg_connection *nc, const char *path,
-                               const struct mg_serve_http_opts *opts) {
+static void mg_handle_ssi_request(struct mg_connection *nc, const char *path,
+                                  const struct mg_serve_http_opts *opts) {
   (void) path;
   (void) opts;
-  send_http_error(nc, 500, "SSI disabled");
+  mg_http_send_http_error(nc, 500, "SSI disabled");
 }
 #endif /* MG_DISABLE_SSI */
 
-static void construct_etag(char *buf, size_t buf_len, const cs_stat_t *st) {
+static void mg_http_construct_etag(char *buf, size_t buf_len,
+                                   const cs_stat_t *st) {
   snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"", (unsigned long) st->st_mtime,
            (int64_t) st->st_size);
 }
-static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
+static void mg_gmt_time_string(char *buf, size_t buf_len, time_t *t) {
   strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
 }
 
-static int parse_range_header(const struct mg_str *header, int64_t *a,
-                              int64_t *b) {
+static int mg_http_parse_range_header(const struct mg_str *header, int64_t *a,
+                                      int64_t *b) {
   /*
    * There is no snscanf. Headers are not guaranteed to be NUL-terminated,
    * so we have this. Ugh.
@@ -5598,17 +5650,15 @@ static int parse_range_header(const struct mg_str *header, int64_t *a,
   return result;
 }
 
-static void mg_send_http_file2(struct mg_connection *nc, const char *path,
+static void mg_http_send_file2(struct mg_connection *nc, const char *path,
                                cs_stat_t *st, struct http_message *hm,
                                struct mg_serve_http_opts *opts) {
-  struct proto_data_http *dp;
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   struct mg_str mime_type;
 
   DBG(("%p [%s]", nc, path));
-  free_http_proto_data(nc);
-  if ((dp = (struct proto_data_http *) MG_CALLOC(1, sizeof(*dp))) == NULL) {
-    send_http_error(nc, 500, "Server Error"); /* LCOV_EXCL_LINE */
-  } else if ((dp->fp = fopen(path, "rb")) == NULL) {
+  mg_http_free_proto_data_file(&pd->file);
+  if ((pd->file.fp = fopen(path, "rb")) == NULL) {
     int code;
     switch (errno) {
       case EACCES:
@@ -5620,13 +5670,10 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
       default:
         code = 500;
     };
-    MG_FREE(dp);
-    nc->proto_data = NULL;
-    send_http_error(nc, code, "Open failed");
+    mg_http_send_http_error(nc, code, "Open failed");
   } else if (mg_match_prefix(opts->ssi_pattern, strlen(opts->ssi_pattern),
                              path) > 0) {
-    nc->proto_data = (void *) dp;
-    handle_ssi_request(nc, path, opts);
+    mg_handle_ssi_request(nc, path, opts);
   } else {
     char etag[50], current_time[50], last_modified[50], range[50];
     time_t t = time(NULL);
@@ -5637,7 +5684,7 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
     /* Handle Range header */
     range[0] = '\0';
     if (range_hdr != NULL &&
-        (n = parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
+        (n = mg_http_parse_range_header(range_hdr, &r1, &r2)) > 0 && r1 >= 0 &&
         r2 >= 0) {
       /* If range is specified like "400-", set second limit to content len */
       if (n == 1) {
@@ -5655,14 +5702,14 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
         snprintf(range, sizeof(range), "Content-Range: bytes %" INT64_FMT
                                        "-%" INT64_FMT "/%" INT64_FMT "\r\n",
                  r1, r1 + cl - 1, (int64_t) st->st_size);
-        fseeko(dp->fp, r1, SEEK_SET);
+        fseeko(pd->file.fp, r1, SEEK_SET);
       }
     }
 
-    construct_etag(etag, sizeof(etag), st);
-    gmt_time_string(current_time, sizeof(current_time), &t);
-    gmt_time_string(last_modified, sizeof(last_modified), &st->st_mtime);
-    mime_type = get_mime_type(path, "text/plain", opts);
+    mg_http_construct_etag(etag, sizeof(etag), st);
+    mg_gmt_time_string(current_time, sizeof(current_time), &t);
+    mg_gmt_time_string(last_modified, sizeof(last_modified), &st->st_mtime);
+    mime_type = mg_get_mime_type(path, "text/plain", opts);
     /*
      * Content length casted to size_t because:
      * 1) that's the maximum buffer size anyway
@@ -5685,10 +5732,9 @@ static void mg_send_http_file2(struct mg_connection *nc, const char *path,
               current_time, last_modified, (int) mime_type.len, mime_type.p,
               (size_t) cl, range, etag);
 
-    nc->proto_data = (void *) dp;
-    dp->cl = cl;
-    dp->type = DATA_FILE;
-    transfer_file_data(nc);
+    pd->file.cl = cl;
+    pd->file.type = DATA_FILE;
+    mg_http_transfer_file_data(nc);
   }
 }
 
@@ -5854,9 +5900,9 @@ int mg_http_parse_header(struct mg_str *hdr, const char *var_name, char *buf,
 }
 
 #ifndef MG_DISABLE_FILESYSTEM
-static int is_file_hidden(const char *path,
-                          const struct mg_serve_http_opts *opts,
-                          int exclude_specials) {
+static int mg_is_file_hidden(const char *path,
+                             const struct mg_serve_http_opts *opts,
+                             int exclude_specials) {
   const char *p1 = opts->per_directory_auth_file;
   const char *p2 = opts->hidden_file_pattern;
 
@@ -5873,11 +5919,11 @@ static int is_file_hidden(const char *path,
 }
 
 #ifndef MG_DISABLE_HTTP_DIGEST_AUTH
-static void mkmd5resp(const char *method, size_t method_len, const char *uri,
-                      size_t uri_len, const char *ha1, size_t ha1_len,
-                      const char *nonce, size_t nonce_len, const char *nc,
-                      size_t nc_len, const char *cnonce, size_t cnonce_len,
-                      const char *qop, size_t qop_len, char *resp) {
+static void mg_mkmd5resp(const char *method, size_t method_len, const char *uri,
+                         size_t uri_len, const char *ha1, size_t ha1_len,
+                         const char *nonce, size_t nonce_len, const char *nc,
+                         size_t nc_len, const char *cnonce, size_t cnonce_len,
+                         const char *qop, size_t qop_len, char *resp) {
   static const char colon[] = ":";
   static const size_t one = 1;
   char ha2[33];
@@ -5900,9 +5946,9 @@ int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
   cs_md5(ha1, user, (size_t) strlen(user), colon, one, auth_domain,
          (size_t) strlen(auth_domain), colon, one, passwd,
          (size_t) strlen(passwd), NULL);
-  mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
-            cnonce, strlen(cnonce), "1", one, cnonce, strlen(cnonce), qop,
-            sizeof(qop) - 1, resp);
+  mg_mkmd5resp(method, strlen(method), uri, strlen(uri), ha1, sizeof(ha1) - 1,
+               cnonce, strlen(cnonce), "1", one, cnonce, strlen(cnonce), qop,
+               sizeof(qop) - 1, resp);
   return snprintf(buf, buf_len,
                   "Authorization: Digest username=\"%s\","
                   "realm=\"%s\",uri=\"%s\",qop=%s,nc=1,cnonce=%s,"
@@ -5916,7 +5962,7 @@ int mg_http_create_digest_auth_header(char *buf, size_t buf_len,
  * to prevent replay attacks.
  * Assumption: nonce is a hexadecimal number of seconds since 1970.
  */
-static int check_nonce(const char *nonce) {
+static int mg_check_nonce(const char *nonce) {
   unsigned long now = (unsigned long) time(NULL);
   unsigned long val = (unsigned long) strtoul(nonce, NULL, 16);
   return now < val || now - val < 3600;
@@ -5943,7 +5989,7 @@ static int mg_http_check_digest_auth(struct http_message *hm,
       mg_http_parse_header(hdr, "qop", qop, sizeof(qop)) == 0 ||
       mg_http_parse_header(hdr, "nc", nc, sizeof(nc)) == 0 ||
       mg_http_parse_header(hdr, "nonce", nonce, sizeof(nonce)) == 0 ||
-      check_nonce(nonce) == 0) {
+      mg_check_nonce(nonce) == 0) {
     return 0;
   }
 
@@ -5958,7 +6004,7 @@ static int mg_http_check_digest_auth(struct http_message *hm,
         /* NOTE(lsm): due to a bug in MSIE, we do not compare URIs */
         strcmp(auth_domain, f_domain) == 0) {
       /* User and domain matched, check the password */
-      mkmd5resp(
+      mg_mkmd5resp(
           hm->method.p, hm->method.len, hm->uri.p,
           hm->uri.len + (hm->query_string.len ? hm->query_string.len + 1 : 0),
           f_ha1, strlen(f_ha1), nonce, strlen(nonce), nc, strlen(nc), cnonce,
@@ -5971,9 +6017,10 @@ static int mg_http_check_digest_auth(struct http_message *hm,
   return 0;
 }
 
-static int is_authorized(struct http_message *hm, const char *path,
-                         int is_directory, const char *domain,
-                         const char *passwords_file, int is_global_pass_file) {
+static int mg_is_authorized(struct http_message *hm, const char *path,
+                            int is_directory, const char *domain,
+                            const char *passwords_file,
+                            int is_global_pass_file) {
   char buf[MG_MAX_PATH];
   const char *p;
   FILE *fp;
@@ -6004,9 +6051,10 @@ static int is_authorized(struct http_message *hm, const char *path,
   return authorized;
 }
 #else
-static int is_authorized(struct http_message *hm, const char *path,
-                         int is_directory, const char *domain,
-                         const char *passwords_file, int is_global_pass_file) {
+static int mg_is_authorized(struct http_message *hm, const char *path,
+                            int is_directory, const char *domain,
+                            const char *passwords_file,
+                            int is_global_pass_file) {
   (void) hm;
   (void) path;
   (void) is_directory;
@@ -6040,7 +6088,7 @@ static size_t mg_url_encode(const char *src, size_t s_len, char *dst,
   return j;
 }
 
-static void escape(const char *src, char *dst, size_t dst_len) {
+static void mg_escape(const char *src, char *dst, size_t dst_len) {
   size_t n = 0;
   while (*src != '\0' && n + 5 < dst_len) {
     unsigned char ch = *(unsigned char *) src++;
@@ -6053,8 +6101,8 @@ static void escape(const char *src, char *dst, size_t dst_len) {
   dst[n] = '\0';
 }
 
-static void print_dir_entry(struct mg_connection *nc, const char *file_name,
-                            cs_stat_t *stp) {
+static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
+                               cs_stat_t *stp) {
   char size[64], mod[64], href[MAX_PATH_SIZE * 3], path[MAX_PATH_SIZE];
   int64_t fsize = stp->st_size;
   int is_dir = S_ISDIR(stp->st_mode);
@@ -6078,7 +6126,7 @@ static void print_dir_entry(struct mg_connection *nc, const char *file_name,
     }
   }
   strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&stp->st_mtime));
-  escape(file_name, path, sizeof(path));
+  mg_escape(file_name, path, sizeof(path));
   mg_url_encode(file_name, strlen(file_name), href, sizeof(href));
   mg_printf_http_chunk(nc,
                        "<tr><td><a href=\"%s%s\">%s%s</a></td>"
@@ -6087,10 +6135,10 @@ static void print_dir_entry(struct mg_connection *nc, const char *file_name,
                        size);
 }
 
-static void scan_directory(struct mg_connection *nc, const char *dir,
-                           const struct mg_serve_http_opts *opts,
-                           void (*func)(struct mg_connection *, const char *,
-                                        cs_stat_t *)) {
+static void mg_scan_directory(struct mg_connection *nc, const char *dir,
+                              const struct mg_serve_http_opts *opts,
+                              void (*func)(struct mg_connection *, const char *,
+                                           cs_stat_t *)) {
   char path[MAX_PATH_SIZE];
   cs_stat_t st;
   struct dirent *dp;
@@ -6100,7 +6148,7 @@ static void scan_directory(struct mg_connection *nc, const char *dir,
   if ((dirp = (opendir(dir))) != NULL) {
     while ((dp = readdir(dirp)) != NULL) {
       /* Do not show current dir and hidden files */
-      if (is_file_hidden((const char *) dp->d_name, opts, 1)) {
+      if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
         continue;
       }
       snprintf(path, sizeof(path), "%s/%s", dir, dp->d_name);
@@ -6114,9 +6162,9 @@ static void scan_directory(struct mg_connection *nc, const char *dir,
   }
 }
 
-static void send_directory_listing(struct mg_connection *nc, const char *dir,
-                                   struct http_message *hm,
-                                   struct mg_serve_http_opts *opts) {
+static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,
+                                      struct http_message *hm,
+                                      struct mg_serve_http_opts *opts) {
   static const char *sort_js_code =
       "<script>function srt(tb, col) {"
       "var tr = Array.prototype.slice.call(tb.rows, 0),"
@@ -6149,7 +6197,7 @@ static void send_directory_listing(struct mg_connection *nc, const char *dir,
       "<tr><td colspan=\"3\"><hr></td></tr></thead><tbody id=tb>",
       (int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
       (int) hm->uri.len, hm->uri.p);
-  scan_directory(nc, dir, opts, print_dir_entry);
+  mg_scan_directory(nc, dir, opts, mg_print_dir_entry);
   mg_printf_http_chunk(nc, "%s", "</tbody></body></html>");
   mg_send_http_chunk(nc, "", 0);
   /* TODO(rojer): Remove when cesanta/dev/issues/197 is fixed. */
@@ -6158,11 +6206,11 @@ static void send_directory_listing(struct mg_connection *nc, const char *dir,
 #endif /* MG_DISABLE_DIRECTORY_LISTING */
 
 #ifndef MG_DISABLE_DAV
-static void print_props(struct mg_connection *nc, const char *name,
-                        cs_stat_t *stp) {
+static void mg_print_props(struct mg_connection *nc, const char *name,
+                           cs_stat_t *stp) {
   char mtime[64], buf[MAX_PATH_SIZE * 3];
   time_t t = stp->st_mtime; /* store in local variable for NDK compile */
-  gmt_time_string(mtime, sizeof(mtime), &t);
+  mg_gmt_time_string(mtime, sizeof(mtime), &t);
   mg_url_encode(name, strlen(name), buf, sizeof(buf));
   mg_printf(nc,
             "<d:response>"
@@ -6181,9 +6229,9 @@ static void print_props(struct mg_connection *nc, const char *name,
             (int64_t) stp->st_size, mtime);
 }
 
-static void handle_propfind(struct mg_connection *nc, const char *path,
-                            cs_stat_t *stp, struct http_message *hm,
-                            struct mg_serve_http_opts *opts) {
+static void mg_handle_propfind(struct mg_connection *nc, const char *path,
+                               cs_stat_t *stp, struct http_message *hm,
+                               struct mg_serve_http_opts *opts) {
   static const char header[] =
       "HTTP/1.1 207 Multi-Status\r\n"
       "Connection: close\r\n"
@@ -6201,9 +6249,9 @@ static void handle_propfind(struct mg_connection *nc, const char *path,
     char uri[MAX_PATH_SIZE];
     mg_send(nc, header, sizeof(header) - 1);
     snprintf(uri, sizeof(uri), "%.*s", (int) hm->uri.len, hm->uri.p);
-    print_props(nc, uri, stp);
+    mg_print_props(nc, uri, stp);
     if (S_ISDIR(stp->st_mode) && (depth == NULL || mg_vcmp(depth, "0") != 0)) {
-      scan_directory(nc, path, opts, print_props);
+      mg_scan_directory(nc, path, opts, mg_print_props);
     }
     mg_send(nc, footer, sizeof(footer) - 1);
     nc->flags |= MG_F_SEND_AND_CLOSE;
@@ -6222,7 +6270,7 @@ static void handle_propfind(struct mg_connection *nc, const char *path,
  * NOTE: that is not DAV LOCK imlementation, it is just a way to shut up
  * Windows native DAV client. This is why FAKE LOCK is not enabed by default
  */
-static void handle_lock(struct mg_connection *nc, const char *path) {
+static void mg_handle_lock(struct mg_connection *nc, const char *path) {
   static const char *reply =
       "HTTP/1.1 207 Multi-Status\r\n"
       "Connection: close\r\n"
@@ -6244,8 +6292,8 @@ static void handle_lock(struct mg_connection *nc, const char *path) {
 }
 #endif
 
-static void handle_mkcol(struct mg_connection *nc, const char *path,
-                         struct http_message *hm) {
+static void mg_handle_mkcol(struct mg_connection *nc, const char *path,
+                            struct http_message *hm) {
   int status_code = 500;
   if (hm->body.len != (size_t) ~0 && hm->body.len > 0) {
     status_code = 415;
@@ -6260,11 +6308,11 @@ static void handle_mkcol(struct mg_connection *nc, const char *path,
   } else {
     status_code = 500;
   }
-  send_http_error(nc, status_code, NULL);
+  mg_http_send_http_error(nc, status_code, NULL);
 }
 
-static int remove_directory(const struct mg_serve_http_opts *opts,
-                            const char *dir) {
+static int mg_remove_directory(const struct mg_serve_http_opts *opts,
+                               const char *dir) {
   char path[MAX_PATH_SIZE];
   struct dirent *dp;
   cs_stat_t st;
@@ -6273,13 +6321,13 @@ static int remove_directory(const struct mg_serve_http_opts *opts,
   if ((dirp = opendir(dir)) == NULL) return 0;
 
   while ((dp = readdir(dirp)) != NULL) {
-    if (is_file_hidden((const char *) dp->d_name, opts, 1)) {
+    if (mg_is_file_hidden((const char *) dp->d_name, opts, 1)) {
       continue;
     }
     snprintf(path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
     mg_stat(path, &st);
     if (S_ISDIR(st.st_mode)) {
-      remove_directory(opts, path);
+      mg_remove_directory(opts, path);
     } else {
       remove(path);
     }
@@ -6290,12 +6338,12 @@ static int remove_directory(const struct mg_serve_http_opts *opts,
   return 1;
 }
 
-static void handle_move(struct mg_connection *c,
-                        const struct mg_serve_http_opts *opts, const char *path,
-                        struct http_message *hm) {
+static void mg_handle_move(struct mg_connection *c,
+                           const struct mg_serve_http_opts *opts,
+                           const char *path, struct http_message *hm) {
   const struct mg_str *dest = mg_get_http_header(hm, "Destination");
   if (dest == NULL) {
-    send_http_error(c, 411, NULL);
+    mg_http_send_http_error(c, 411, NULL);
   } else {
     const char *p = (char *) memchr(dest->p, '/', dest->len);
     if (p != NULL && p[1] == '/' &&
@@ -6304,34 +6352,34 @@ static void handle_move(struct mg_connection *c,
       snprintf(buf, sizeof(buf), "%s%.*s", opts->dav_document_root,
                (int) (dest->p + dest->len - p), p);
       if (rename(path, buf) == 0) {
-        send_http_error(c, 200, NULL);
+        mg_http_send_http_error(c, 200, NULL);
       } else {
-        send_http_error(c, 418, NULL);
+        mg_http_send_http_error(c, 418, NULL);
       }
     } else {
-      send_http_error(c, 500, NULL);
+      mg_http_send_http_error(c, 500, NULL);
     }
   }
 }
 
-static void handle_delete(struct mg_connection *nc,
-                          const struct mg_serve_http_opts *opts,
-                          const char *path) {
+static void mg_handle_delete(struct mg_connection *nc,
+                             const struct mg_serve_http_opts *opts,
+                             const char *path) {
   cs_stat_t st;
   if (mg_stat(path, &st) != 0) {
-    send_http_error(nc, 404, NULL);
+    mg_http_send_http_error(nc, 404, NULL);
   } else if (S_ISDIR(st.st_mode)) {
-    remove_directory(opts, path);
-    send_http_error(nc, 204, NULL);
+    mg_remove_directory(opts, path);
+    mg_http_send_http_error(nc, 204, NULL);
   } else if (remove(path) == 0) {
-    send_http_error(nc, 204, NULL);
+    mg_http_send_http_error(nc, 204, NULL);
   } else {
-    send_http_error(nc, 423, NULL);
+    mg_http_send_http_error(nc, 423, NULL);
   }
 }
 
 /* Return -1 on error, 1 on success. */
-static int create_itermediate_directories(const char *path) {
+static int mg_create_itermediate_directories(const char *path) {
   const char *s;
 
   /* Create intermediate directories if they do not exist */
@@ -6350,47 +6398,43 @@ static int create_itermediate_directories(const char *path) {
   return 1;
 }
 
-static void handle_put(struct mg_connection *nc, const char *path,
-                       struct http_message *hm) {
+static void mg_handle_put(struct mg_connection *nc, const char *path,
+                          struct http_message *hm) {
+  struct mg_http_proto_data *pd = mg_http_get_proto_data(nc);
   cs_stat_t st;
   const struct mg_str *cl_hdr = mg_get_http_header(hm, "Content-Length");
   int rc, status_code = mg_stat(path, &st) == 0 ? 200 : 201;
-  struct proto_data_http *dp = (struct proto_data_http *) nc->proto_data;
 
-  free_http_proto_data(nc);
-  if ((rc = create_itermediate_directories(path)) == 0) {
+  mg_http_free_proto_data_file(&pd->file);
+  if ((rc = mg_create_itermediate_directories(path)) == 0) {
     mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
   } else if (rc == -1) {
-    send_http_error(nc, 500, NULL);
+    mg_http_send_http_error(nc, 500, NULL);
   } else if (cl_hdr == NULL) {
-    send_http_error(nc, 411, NULL);
-  } else if ((dp = (struct proto_data_http *) MG_CALLOC(1, sizeof(*dp))) ==
-             NULL) {
-    send_http_error(nc, 500, NULL); /* LCOV_EXCL_LINE */
-  } else if ((dp->fp = fopen(path, "w+b")) == NULL) {
-    send_http_error(nc, 500, NULL);
-    free_http_proto_data(nc);
+    mg_http_send_http_error(nc, 411, NULL);
+  } else if ((pd->file.fp = fopen(path, "w+b")) == NULL) {
+    mg_http_send_http_error(nc, 500, NULL);
   } else {
     const struct mg_str *range_hdr = mg_get_http_header(hm, "Content-Range");
     int64_t r1 = 0, r2 = 0;
-    dp->type = DATA_PUT;
-    mg_set_close_on_exec(fileno(dp->fp));
-    dp->cl = to64(cl_hdr->p);
-    if (range_hdr != NULL && parse_range_header(range_hdr, &r1, &r2) > 0) {
+    pd->file.type = DATA_PUT;
+    mg_set_close_on_exec(fileno(pd->file.fp));
+    pd->file.cl = to64(cl_hdr->p);
+    if (range_hdr != NULL &&
+        mg_http_parse_range_header(range_hdr, &r1, &r2) > 0) {
       status_code = 206;
-      fseeko(dp->fp, r1, SEEK_SET);
-      dp->cl = r2 > r1 ? r2 - r1 + 1 : dp->cl - r1;
+      fseeko(pd->file.fp, r1, SEEK_SET);
+      pd->file.cl = r2 > r1 ? r2 - r1 + 1 : pd->file.cl - r1;
     }
     mg_printf(nc, "HTTP/1.1 %d OK\r\nContent-Length: 0\r\n\r\n", status_code);
-    nc->proto_data = dp;
     /* Remove HTTP request from the mbuf, leave only payload */
     mbuf_remove(&nc->recv_mbuf, hm->message.len - hm->body.len);
-    transfer_file_data(nc);
+    mg_http_transfer_file_data(nc);
   }
 }
 #endif /* MG_DISABLE_DAV */
 
-static int is_dav_request(const struct mg_str *s) {
+static int mg_is_dav_request(const struct mg_str *s) {
   static const char *methods[] = {"PUT", "DELETE", "MKCOL", "PROPFIND", "MOVE"
 #ifdef MG_ENABLE_FAKE_DAVLOCK
                                   ,
@@ -6415,8 +6459,8 @@ static int is_dav_request(const struct mg_str *s) {
  * appended to the `path`, stat-ed, and result of `stat()` passed to `stp`.
  * If index file is not found, then `path` and `stp` remain unchanged.
  */
-MG_INTERNAL void find_index_file(const char *path, const char *list,
-                                 char **index_file, cs_stat_t *stp) {
+MG_INTERNAL void mg_find_index_file(const char *path, const char *list,
+                                    char **index_file, cs_stat_t *stp) {
   struct mg_str vec;
   size_t path_len = strlen(path);
   int found = 0;
@@ -6446,9 +6490,9 @@ MG_INTERNAL void find_index_file(const char *path, const char *list,
   DBG(("[%s] [%s]", path, (*index_file ? *index_file : "")));
 }
 
-static int send_port_based_redirect(struct mg_connection *c,
-                                    struct http_message *hm,
-                                    const struct mg_serve_http_opts *opts) {
+static int mg_http_send_port_based_redirect(
+    struct mg_connection *c, struct http_message *hm,
+    const struct mg_serve_http_opts *opts) {
   const char *rewrites = opts->url_rewrites;
   struct mg_str a, b;
   char local_port[20] = {'%'};
@@ -6521,7 +6565,7 @@ MG_INTERNAL int mg_uri_to_local_path(struct http_message *hm,
     /* If no rewrite rules matched, use DAV or regular document root. */
     if (root.p == NULL) {
 #ifndef MG_DISABLE_DAV
-      if (opts->dav_document_root != NULL && is_dav_request(&hm->method)) {
+      if (opts->dav_document_root != NULL && mg_is_dav_request(&hm->method)) {
         root.p = opts->dav_document_root;
         root.len = strlen(opts->dav_document_root);
       } else
@@ -6627,25 +6671,25 @@ out:
 
 #ifndef MG_DISABLE_CGI
 #ifdef _WIN32
-struct threadparam {
+struct mg_threadparam {
   sock_t s;
   HANDLE hPipe;
 };
 
-static int wait_until_ready(sock_t sock, int for_read) {
+static int mg_wait_until_ready(sock_t sock, int for_read) {
   fd_set set;
   FD_ZERO(&set);
   FD_SET(sock, &set);
   return select(sock + 1, for_read ? &set : 0, for_read ? 0 : &set, 0, 0) == 1;
 }
 
-static void *push_to_stdin(void *arg) {
-  struct threadparam *tp = (struct threadparam *) arg;
+static void *mg_push_to_stdin(void *arg) {
+  struct mg_threadparam *tp = (struct mg_threadparam *) arg;
   int n, sent, stop = 0;
   DWORD k;
   char buf[BUFSIZ];
 
-  while (!stop && wait_until_ready(tp->s, 1) &&
+  while (!stop && mg_wait_until_ready(tp->s, 1) &&
          (n = recv(tp->s, buf, sizeof(buf), 0)) > 0) {
     if (n == -1 && GetLastError() == WSAEWOULDBLOCK) continue;
     for (sent = 0; !stop && sent < n; sent += k) {
@@ -6659,15 +6703,15 @@ static void *push_to_stdin(void *arg) {
   return NULL;
 }
 
-static void *pull_from_stdout(void *arg) {
-  struct threadparam *tp = (struct threadparam *) arg;
+static void *mg_pull_from_stdout(void *arg) {
+  struct mg_threadparam *tp = (struct mg_threadparam *) arg;
   int k = 0, stop = 0;
   DWORD n, sent;
   char buf[BUFSIZ];
 
   while (!stop && ReadFile(tp->hPipe, buf, sizeof(buf), &n, NULL)) {
     for (sent = 0; !stop && sent < n; sent += k) {
-      if (wait_until_ready(tp->s, 0) &&
+      if (mg_wait_until_ready(tp->s, 0) &&
           (k = send(tp->s, buf + sent, n - sent, 0)) <= 0)
         stop = 1;
     }
@@ -6681,9 +6725,9 @@ static void *pull_from_stdout(void *arg) {
   return NULL;
 }
 
-static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
-                               void *(*func)(void *)) {
-  struct threadparam *tp = (struct threadparam *) MG_MALLOC(sizeof(*tp));
+static void mg_spawn_stdio_thread(sock_t sock, HANDLE hPipe,
+                                  void *(*func)(void *)) {
+  struct mg_threadparam *tp = (struct mg_threadparam *) MG_MALLOC(sizeof(*tp));
   if (tp != NULL) {
     tp->s = sock;
     tp->hPipe = hPipe;
@@ -6691,15 +6735,16 @@ static void spawn_stdio_thread(sock_t sock, HANDLE hPipe,
   }
 }
 
-static void abs_path(const char *utf8_path, char *abs_path, size_t len) {
+static void mg_abs_path(const char *utf8_path, char *abs_path, size_t len) {
   wchar_t buf[MAX_PATH_SIZE], buf2[MAX_PATH_SIZE];
   to_wchar(utf8_path, buf, ARRAY_SIZE(buf));
   GetFullPathNameW(buf, ARRAY_SIZE(buf2), buf2, NULL);
   WideCharToMultiByte(CP_UTF8, 0, buf2, wcslen(buf2) + 1, abs_path, len, 0, 0);
 }
 
-static pid_t start_process(const char *interp, const char *cmd, const char *env,
-                           const char *envp[], const char *dir, sock_t sock) {
+static pid_t mg_start_process(const char *interp, const char *cmd,
+                              const char *env, const char *envp[],
+                              const char *dir, sock_t sock) {
   STARTUPINFOW si;
   PROCESS_INFORMATION pi;
   HANDLE a[2], b[2], me = GetCurrentProcess();
@@ -6737,13 +6782,13 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
   }
 
   snprintf(buf, sizeof(buf), "%s/%s", dir, cmd);
-  abs_path(buf, buf2, ARRAY_SIZE(buf2));
+  mg_abs_path(buf, buf2, ARRAY_SIZE(buf2));
 
-  abs_path(dir, buf5, ARRAY_SIZE(buf5));
+  mg_abs_path(dir, buf5, ARRAY_SIZE(buf5));
   to_wchar(dir, full_dir, ARRAY_SIZE(full_dir));
 
   if (interp != NULL) {
-    abs_path(interp, buf4, ARRAY_SIZE(buf4));
+    mg_abs_path(interp, buf4, ARRAY_SIZE(buf4));
     snprintf(cmdline, sizeof(cmdline), "%s \"%s\"", buf4, buf2);
   } else {
     snprintf(cmdline, sizeof(cmdline), "\"%s\"", buf2);
@@ -6752,8 +6797,8 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
 
   if (CreateProcessW(NULL, wcmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP,
                      (void *) env, full_dir, &si, &pi) != 0) {
-    spawn_stdio_thread(sock, a[1], push_to_stdin);
-    spawn_stdio_thread(sock, b[0], pull_from_stdout);
+    mg_spawn_stdio_thread(sock, a[1], mg_push_to_stdin);
+    mg_spawn_stdio_thread(sock, b[0], mg_pull_from_stdout);
   } else {
     CloseHandle(a[1]);
     CloseHandle(b[0]);
@@ -6771,8 +6816,9 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
   return pi.hProcess;
 }
 #else
-static pid_t start_process(const char *interp, const char *cmd, const char *env,
-                           const char *envp[], const char *dir, sock_t sock) {
+static pid_t mg_start_process(const char *interp, const char *cmd,
+                              const char *env, const char *envp[],
+                              const char *dir, sock_t sock) {
   char buf[500];
   pid_t pid = fork();
   (void) env;
@@ -6818,7 +6864,7 @@ static pid_t start_process(const char *interp, const char *cmd, const char *env,
  * Append VARIABLE=VALUE\0 string to the buffer, and add a respective
  * pointer into the vars array.
  */
-static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
+static char *mg_addenv(struct mg_cgi_env_block *block, const char *fmt, ...) {
   int n, space;
   char *added = block->buf + block->len;
   va_list ap;
@@ -6844,16 +6890,17 @@ static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
   return added;
 }
 
-static void addenv2(struct cgi_env_block *blk, const char *name) {
+static void mg_addenv2(struct mg_cgi_env_block *blk, const char *name) {
   const char *s;
-  if ((s = getenv(name)) != NULL) addenv(blk, "%s=%s", name, s);
+  if ((s = getenv(name)) != NULL) mg_addenv(blk, "%s=%s", name, s);
 }
 
-static void prepare_cgi_environment(struct mg_connection *nc, const char *prog,
-                                    const struct mg_str *path_info,
-                                    const struct http_message *hm,
-                                    const struct mg_serve_http_opts *opts,
-                                    struct cgi_env_block *blk) {
+static void mg_prepare_cgi_environment(struct mg_connection *nc,
+                                       const char *prog,
+                                       const struct mg_str *path_info,
+                                       const struct http_message *hm,
+                                       const struct mg_serve_http_opts *opts,
+                                       struct mg_cgi_env_block *blk) {
   const char *s;
   struct mg_str *h;
   char *p;
@@ -6863,89 +6910,89 @@ static void prepare_cgi_environment(struct mg_connection *nc, const char *prog,
   blk->nc = nc;
 
   if ((s = getenv("SERVER_NAME")) != NULL) {
-    addenv(blk, "SERVER_NAME=%s", s);
+    mg_addenv(blk, "SERVER_NAME=%s", s);
   } else {
     char buf[100];
     mg_sock_to_str(nc->sock, buf, sizeof(buf), 3);
-    addenv(blk, "SERVER_NAME=%s", buf);
+    mg_addenv(blk, "SERVER_NAME=%s", buf);
   }
-  addenv(blk, "SERVER_ROOT=%s", opts->document_root);
-  addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
-  addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
+  mg_addenv(blk, "SERVER_ROOT=%s", opts->document_root);
+  mg_addenv(blk, "DOCUMENT_ROOT=%s", opts->document_root);
+  mg_addenv(blk, "SERVER_SOFTWARE=%s/%s", "Mongoose", MG_VERSION);
 
   /* Prepare the environment block */
-  addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
-  addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
-  addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
+  mg_addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
+  mg_addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
+  mg_addenv(blk, "%s", "REDIRECT_STATUS=200"); /* For PHP */
 
   /* TODO(lsm): fix this for IPv6 case */
   /*addenv(blk, "SERVER_PORT=%d", ri->remote_port); */
 
-  addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
+  mg_addenv(blk, "REQUEST_METHOD=%.*s", (int) hm->method.len, hm->method.p);
 #if 0
   addenv(blk, "REMOTE_ADDR=%s", ri->remote_ip);
   addenv(blk, "REMOTE_PORT=%d", ri->remote_port);
 #endif
-  addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
-         hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
-         hm->query_string.p);
+  mg_addenv(blk, "REQUEST_URI=%.*s%s%.*s", (int) hm->uri.len, hm->uri.p,
+            hm->query_string.len == 0 ? "" : "?", (int) hm->query_string.len,
+            hm->query_string.p);
 
   s = hm->uri.p + hm->uri.len - path_info->len - 1;
   if (*s == '/') {
     const char *base_name = strrchr(prog, DIRSEP);
-    addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
-           (base_name != NULL ? base_name + 1 : prog));
+    mg_addenv(blk, "SCRIPT_NAME=%.*s/%s", (int) (s - hm->uri.p), hm->uri.p,
+              (base_name != NULL ? base_name + 1 : prog));
   } else {
-    addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
+    mg_addenv(blk, "SCRIPT_NAME=%.*s", (int) (s - hm->uri.p + 1), hm->uri.p);
   }
-  addenv(blk, "SCRIPT_FILENAME=%s", prog);
+  mg_addenv(blk, "SCRIPT_FILENAME=%s", prog);
 
   if (path_info != NULL && path_info->len > 0) {
-    addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
+    mg_addenv(blk, "PATH_INFO=%.*s", (int) path_info->len, path_info->p);
     /* Not really translated... */
-    addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
+    mg_addenv(blk, "PATH_TRANSLATED=%.*s", (int) path_info->len, path_info->p);
   }
 
-  addenv(blk, "HTTPS=%s", nc->ssl != NULL ? "on" : "off");
+  mg_addenv(blk, "HTTPS=%s", nc->ssl != NULL ? "on" : "off");
 
   if ((h = mg_get_http_header((struct http_message *) hm, "Content-Type")) !=
       NULL) {
-    addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
+    mg_addenv(blk, "CONTENT_TYPE=%.*s", (int) h->len, h->p);
   }
 
   if (hm->query_string.len > 0) {
-    addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
-           hm->query_string.p);
+    mg_addenv(blk, "QUERY_STRING=%.*s", (int) hm->query_string.len,
+              hm->query_string.p);
   }
 
   if ((h = mg_get_http_header((struct http_message *) hm, "Content-Length")) !=
       NULL) {
-    addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
+    mg_addenv(blk, "CONTENT_LENGTH=%.*s", (int) h->len, h->p);
   }
 
-  addenv2(blk, "PATH");
-  addenv2(blk, "TMP");
-  addenv2(blk, "TEMP");
-  addenv2(blk, "TMPDIR");
-  addenv2(blk, "PERLLIB");
-  addenv2(blk, MG_ENV_EXPORT_TO_CGI);
+  mg_addenv2(blk, "PATH");
+  mg_addenv2(blk, "TMP");
+  mg_addenv2(blk, "TEMP");
+  mg_addenv2(blk, "TMPDIR");
+  mg_addenv2(blk, "PERLLIB");
+  mg_addenv2(blk, MG_ENV_EXPORT_TO_CGI);
 
 #if defined(_WIN32)
-  addenv2(blk, "COMSPEC");
-  addenv2(blk, "SYSTEMROOT");
-  addenv2(blk, "SystemDrive");
-  addenv2(blk, "ProgramFiles");
-  addenv2(blk, "ProgramFiles(x86)");
-  addenv2(blk, "CommonProgramFiles(x86)");
+  mg_addenv2(blk, "COMSPEC");
+  mg_addenv2(blk, "SYSTEMROOT");
+  mg_addenv2(blk, "SystemDrive");
+  mg_addenv2(blk, "ProgramFiles");
+  mg_addenv2(blk, "ProgramFiles(x86)");
+  mg_addenv2(blk, "CommonProgramFiles(x86)");
 #else
-  addenv2(blk, "LD_LIBRARY_PATH");
+  mg_addenv2(blk, "LD_LIBRARY_PATH");
 #endif /* _WIN32 */
 
   /* Add all headers as HTTP_* variables */
   for (i = 0; hm->header_names[i].len > 0; i++) {
-    p = addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
-               hm->header_names[i].p, (int) hm->header_values[i].len,
-               hm->header_values[i].p);
+    p = mg_addenv(blk, "HTTP_%.*s=%.*s", (int) hm->header_names[i].len,
+                  hm->header_names[i].p, (int) hm->header_values[i].len,
+                  hm->header_values[i].p);
 
     /* Convert variable name into uppercase, and change - to _ */
     for (; *p != '=' && *p != '\0'; p++) {
@@ -6958,8 +7005,8 @@ static void prepare_cgi_environment(struct mg_connection *nc, const char *prog,
   blk->buf[blk->len++] = '\0';
 }
 
-static void cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
-                           void *ev_data) {
+static void mg_cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
+                              void *ev_data) {
   struct mg_connection *nc = (struct mg_connection *) cgi_nc->user_data;
   (void) ev_data;
 
@@ -6982,16 +7029,16 @@ static void cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
        */
       if (nc->flags & MG_F_USER_1) {
         struct mbuf *io = &cgi_nc->recv_mbuf;
-        int len = get_request_len(io->buf, io->len);
+        int len = mg_http_get_request_len(io->buf, io->len);
 
         if (len == 0) break;
         if (len < 0 || io->len > MG_MAX_HTTP_REQUEST_SIZE) {
           cgi_nc->flags |= MG_F_CLOSE_IMMEDIATELY;
-          send_http_error(nc, 500, "Bad headers");
+          mg_http_send_http_error(nc, 500, "Bad headers");
         } else {
           struct http_message hm;
           struct mg_str *h;
-          parse_http_headers(io->buf, io->buf + io->len, io->len, &hm);
+          mg_http_parse_headers(io->buf, io->buf + io->len, io->len, &hm);
           if (mg_get_http_header(&hm, "Location") != NULL) {
             mg_printf(nc, "%s", "HTTP/1.1 302 Moved\r\n");
           } else if ((h = mg_get_http_header(&hm, "Status")) != NULL) {
@@ -7007,25 +7054,23 @@ static void cgi_ev_handler(struct mg_connection *cgi_nc, int ev,
       }
       break;
     case MG_EV_CLOSE:
-      free_http_proto_data(cgi_nc);
+      mg_http_free_proto_data_cgi(&mg_http_get_proto_data(cgi_nc)->cgi);
       nc->flags |= MG_F_SEND_AND_CLOSE;
-      nc->user_data = NULL;
       break;
   }
 }
 
-static void handle_cgi(struct mg_connection *nc, const char *prog,
-                       const struct mg_str *path_info,
-                       const struct http_message *hm,
-                       const struct mg_serve_http_opts *opts) {
-  struct proto_data_http *dp;
-  struct cgi_env_block blk;
+static void mg_handle_cgi(struct mg_connection *nc, const char *prog,
+                          const struct mg_str *path_info,
+                          const struct http_message *hm,
+                          const struct mg_serve_http_opts *opts) {
+  struct mg_cgi_env_block blk;
   char dir[MAX_PATH_SIZE];
   const char *p;
   sock_t fds[2];
 
   DBG(("%p [%s]", nc, prog));
-  prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
+  mg_prepare_cgi_environment(nc, prog, path_info, hm, opts, &blk);
   /*
    * CGI must be executed in its own directory. 'dir' must point to the
    * directory containing executable program, 'p' must point to the
@@ -7047,25 +7092,23 @@ static void handle_cgi(struct mg_connection *nc, const char *prog,
     mg_socketpair(fds, SOCK_STREAM);
   } while (fds[0] == INVALID_SOCKET);
 
-  free_http_proto_data(nc);
-  if ((dp = (struct proto_data_http *) MG_CALLOC(1, sizeof(*dp))) == NULL) {
-    send_http_error(nc, 500, "OOM"); /* LCOV_EXCL_LINE */
-  } else if (start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
-                           fds[1]) != 0) {
+  if (mg_start_process(opts->cgi_interpreter, prog, blk.buf, blk.vars, dir,
+                       fds[1]) != 0) {
     size_t n = nc->recv_mbuf.len - (hm->message.len - hm->body.len);
-    dp->type = DATA_CGI;
-    dp->cgi_nc = mg_add_sock(nc->mgr, fds[0], cgi_ev_handler);
-    dp->cgi_nc->user_data = nc;
-    dp->cgi_nc->proto_data = dp;
+    struct mg_connection *cgi_nc =
+        mg_add_sock(nc->mgr, fds[0], mg_cgi_ev_handler);
+    struct mg_http_proto_data *cgi_pd = mg_http_get_proto_data(cgi_nc);
+    cgi_pd->cgi.cgi_nc = cgi_nc;
+    cgi_pd->cgi.cgi_nc->user_data = nc;
     nc->flags |= MG_F_USER_1;
     /* Push POST data to the CGI */
     if (n > 0 && n < nc->recv_mbuf.len) {
-      mg_send(dp->cgi_nc, hm->body.p, n);
+      mg_send(cgi_pd->cgi.cgi_nc, hm->body.p, n);
     }
     mbuf_remove(&nc->recv_mbuf, nc->recv_mbuf.len);
   } else {
     closesocket(fds[0]);
-    send_http_error(nc, 500, "CGI failure");
+    mg_http_send_http_error(nc, 500, "CGI failure");
   }
 
 #ifndef _WIN32
@@ -7119,7 +7162,7 @@ MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
   struct mg_str *hdr;
   if ((hdr = mg_get_http_header(hm, "If-None-Match")) != NULL) {
     char etag[64];
-    construct_etag(etag, sizeof(etag), st);
+    mg_http_construct_etag(etag, sizeof(etag), st);
     return mg_vcasecmp(hdr, etag) == 0;
   } else if ((hdr = mg_get_http_header(hm, "If-Modified-Since")) != NULL) {
     return st->st_mtime <= mg_parse_date_string(hdr->p);
@@ -7128,8 +7171,8 @@ MG_INTERNAL int mg_is_not_modified(struct http_message *hm, cs_stat_t *st) {
   }
 }
 
-static void mg_send_digest_auth_request(struct mg_connection *c,
-                                        const char *domain) {
+static void mg_http_send_digest_auth_request(struct mg_connection *c,
+                                             const char *domain) {
   mg_printf(c,
             "HTTP/1.1 401 Unauthorized\r\n"
             "WWW-Authenticate: Digest qop=\"auth\", "
@@ -7138,7 +7181,7 @@ static void mg_send_digest_auth_request(struct mg_connection *c,
             domain, (unsigned long) time(NULL));
 }
 
-static void send_options(struct mg_connection *nc) {
+static void mg_http_send_options(struct mg_connection *nc) {
   mg_printf(nc, "%s",
             "HTTP/1.1 200 OK\r\nAllow: GET, POST, HEAD, CONNECT, OPTIONS"
 #ifndef MG_DISABLE_DAV
@@ -7148,7 +7191,7 @@ static void send_options(struct mg_connection *nc) {
   nc->flags |= MG_F_SEND_AND_CLOSE;
 }
 
-static int is_creation_request(const struct http_message *hm) {
+static int mg_is_creation_request(const struct http_message *hm) {
   return mg_vcmp(&hm->method, "MKCOL") == 0 || mg_vcmp(&hm->method, "PUT") == 0;
 }
 
@@ -7156,7 +7199,7 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
                                    const struct mg_str *path_info,
                                    struct http_message *hm,
                                    struct mg_serve_http_opts *opts) {
-  int exists, is_directory, is_dav = is_dav_request(&hm->method);
+  int exists, is_directory, is_dav = mg_is_dav_request(&hm->method);
   int is_cgi;
   char *index_file = NULL;
   cs_stat_t st;
@@ -7164,7 +7207,8 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
   exists = (mg_stat(path, &st) == 0);
   is_directory = exists && S_ISDIR(st.st_mode);
 
-  if (is_directory) find_index_file(path, opts->index_files, &index_file, &st);
+  if (is_directory)
+    mg_find_index_file(path, opts->index_files, &index_file, &st);
 
   is_cgi =
       (mg_match_prefix(opts->cgi_file_pattern, strlen(opts->cgi_file_pattern),
@@ -7185,68 +7229,69 @@ MG_INTERNAL void mg_send_http_file(struct mg_connection *nc, char *path,
 
   /* If we have path_info, the only way to handle it is CGI. */
   if (path_info->len > 0 && !is_cgi) {
-    send_http_error(nc, 501, NULL);
+    mg_http_send_http_error(nc, 501, NULL);
     return;
   } else if (is_cgi) {
 #if !defined(MG_DISABLE_CGI)
-    handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
+    mg_handle_cgi(nc, index_file ? index_file : path, path_info, hm, opts);
 #else
-    send_http_error(nc, 501, NULL);
+    mg_http_send_http_error(nc, 501, NULL);
 #endif /* MG_DISABLE_CGI */
     MG_FREE(index_file);
     return;
   }
 
   if (is_dav && opts->dav_document_root == NULL) {
-    send_http_error(nc, 501, NULL);
-  } else if (!is_authorized(hm, path, is_directory, opts->auth_domain,
-                            opts->global_auth_file, 1) ||
-             !is_authorized(hm, path, is_directory, opts->auth_domain,
-                            opts->per_directory_auth_file, 0)) {
-    mg_send_digest_auth_request(nc, opts->auth_domain);
-  } else if ((!exists || is_file_hidden(path, opts, 0 /* specials are ok */)) &&
-             !is_creation_request(hm)) {
-    send_http_error(nc, 404, NULL);
+    mg_http_send_http_error(nc, 501, NULL);
+  } else if (!mg_is_authorized(hm, path, is_directory, opts->auth_domain,
+                               opts->global_auth_file, 1) ||
+             !mg_is_authorized(hm, path, is_directory, opts->auth_domain,
+                               opts->per_directory_auth_file, 0)) {
+    mg_http_send_digest_auth_request(nc, opts->auth_domain);
+  } else if ((!exists ||
+              mg_is_file_hidden(path, opts, 0 /* specials are ok */)) &&
+             !mg_is_creation_request(hm)) {
+    mg_http_send_http_error(nc, 404, NULL);
 #ifndef MG_DISABLE_DAV
   } else if (!mg_vcmp(&hm->method, "PROPFIND")) {
-    handle_propfind(nc, path, &st, hm, opts);
+    mg_handle_propfind(nc, path, &st, hm, opts);
 #ifndef MG_DISABLE_DAV_AUTH
   } else if (is_dav &&
              (opts->dav_auth_file == NULL ||
               (strcmp(opts->dav_auth_file, "-") != 0 &&
-               !is_authorized(hm, path, is_directory, opts->auth_domain,
-                              opts->dav_auth_file, 1)))) {
-    mg_send_digest_auth_request(nc, opts->auth_domain);
+               !mg_is_authorized(hm, path, is_directory, opts->auth_domain,
+                                 opts->dav_auth_file, 1)))) {
+    mg_http_send_digest_auth_request(nc, opts->auth_domain);
 #endif
   } else if (!mg_vcmp(&hm->method, "MKCOL")) {
-    handle_mkcol(nc, path, hm);
+    mg_handle_mkcol(nc, path, hm);
   } else if (!mg_vcmp(&hm->method, "DELETE")) {
-    handle_delete(nc, opts, path);
+    mg_handle_delete(nc, opts, path);
   } else if (!mg_vcmp(&hm->method, "PUT")) {
-    handle_put(nc, path, hm);
+    mg_handle_put(nc, path, hm);
   } else if (!mg_vcmp(&hm->method, "MOVE")) {
-    handle_move(nc, opts, path, hm);
+    mg_handle_move(nc, opts, path, hm);
 #ifdef MG_ENABLE_FAKE_DAVLOCK
   } else if (!mg_vcmp(&hm->method, "LOCK")) {
-    handle_lock(nc, path);
+    mg_handle_lock(nc, path);
 #endif
 #endif
   } else if (!mg_vcmp(&hm->method, "OPTIONS")) {
-    send_options(nc);
+    mg_http_send_options(nc);
   } else if (is_directory && index_file == NULL) {
 #ifndef MG_DISABLE_DIRECTORY_LISTING
     if (strcmp(opts->enable_directory_listing, "yes") == 0) {
-      send_directory_listing(nc, path, hm, opts);
+      mg_send_directory_listing(nc, path, hm, opts);
     } else {
-      send_http_error(nc, 403, NULL);
+      mg_http_send_http_error(nc, 403, NULL);
     }
 #else
-    send_http_error(nc, 501, NULL);
+    mg_http_send_http_error(nc, 501, NULL);
 #endif
   } else if (mg_is_not_modified(hm, &st)) {
-    send_http_error(nc, 304, "Not Modified");
+    mg_http_send_http_error(nc, 304, "Not Modified");
   } else {
-    mg_send_http_file2(nc, index_file ? index_file : path, &st, hm, opts);
+    mg_http_send_file2(nc, index_file ? index_file : path, &st, hm, opts);
   }
   MG_FREE(index_file);
 }
@@ -7259,12 +7304,12 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
 
   if (mg_check_ip_acl(opts.ip_acl, remote_ip) != 1) {
     /* Not allowed to connect */
-    send_http_error(nc, 403, NULL);
+    mg_http_send_http_error(nc, 403, NULL);
     nc->flags |= MG_F_SEND_AND_CLOSE;
     return;
   }
 
-  if (send_port_based_redirect(nc, hm, &opts)) {
+  if (mg_http_send_port_based_redirect(nc, hm, &opts)) {
     return;
   }
 
@@ -7288,11 +7333,11 @@ void mg_serve_http(struct mg_connection *nc, struct http_message *hm,
   }
   /* Normalize path - resolve "." and ".." (in-place). */
   if (!mg_normalize_uri_path(&hm->uri, &hm->uri)) {
-    send_http_error(nc, 400, NULL);
+    mg_http_send_http_error(nc, 400, NULL);
     return;
   }
   if (mg_uri_to_local_path(hm, &opts, &path, &path_info) == 0) {
-    send_http_error(nc, 404, NULL);
+    mg_http_send_http_error(nc, 404, NULL);
     return;
   }
   mg_send_http_file(nc, path, &path_info, hm, &opts);
@@ -7382,7 +7427,7 @@ cleanup:
   return nc;
 }
 
-static size_t get_line_len(const char *buf, size_t buf_len) {
+static size_t mg_get_line_len(const char *buf, size_t buf_len) {
   size_t len = 0;
   while (len < buf_len && buf[len] != '\n') len++;
   return buf[len] == '\n' ? len + 1 : 0;
@@ -7396,15 +7441,15 @@ size_t mg_parse_multipart(const char *buf, size_t buf_len, char *var_name,
   size_t hl, bl, n, ll, pos, cdl = sizeof(cd) - 1;
 
   if (buf == NULL || buf_len <= 0) return 0;
-  if ((hl = get_request_len(buf, buf_len)) <= 0) return 0;
+  if ((hl = mg_http_get_request_len(buf, buf_len)) <= 0) return 0;
   if (buf[0] != '-' || buf[1] != '-' || buf[2] == '\n') return 0;
 
   /* Get boundary length */
-  bl = get_line_len(buf, buf_len);
+  bl = mg_get_line_len(buf, buf_len);
 
   /* Loop through headers, fetch variable name and file name */
   var_name[0] = file_name[0] = '\0';
-  for (n = bl; (ll = get_line_len(buf + n, hl - n)) > 0; n += ll) {
+  for (n = bl; (ll = mg_get_line_len(buf + n, hl - n)) > 0; n += ll) {
     if (mg_ncasecmp(cd, buf + n, cdl) == 0) {
       struct mg_str header;
       header.p = buf + n + cdl;
diff --git a/mongoose.h b/mongoose.h
index ce45389ba..242c5c1ea 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -1075,8 +1075,9 @@ struct mg_connection {
   double ev_timer_time;             /* Timestamp of the future MG_EV_TIMER */
   mg_event_handler_t proto_handler; /* Protocol-specific event handler */
   void *proto_data;                 /* Protocol-specific data */
-  mg_event_handler_t handler;       /* Event handler function */
-  void *user_data;                  /* User-specific data */
+  void (*proto_data_destructor)(void *proto_data);
+  mg_event_handler_t handler; /* Event handler function */
+  void *user_data;            /* User-specific data */
   union {
     void *v;
     /*
@@ -1088,9 +1089,6 @@ struct mg_connection {
   void *priv_2;          /* Used by mg_enable_multithreading() */
   struct mbuf endpoints; /* Used by mg_register_http_endpoint */
   void *mgr_data;        /* Implementation-specific event manager's data. */
-#ifdef MG_ENABLE_HTTP_STREAMING_MULTIPART
-  struct mbuf strm_state; /* Used by multi-part streaming */
-#endif
   unsigned long flags;
 /* Flags set by Mongoose */
 #define MG_F_LISTENING (1 << 0)          /* This connection is listening */
-- 
GitLab