From 2ac970fa16325417a8990c632a3cb9ec85929eef Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Sat, 1 Mar 2014 01:17:39 +0000
Subject: [PATCH] Moving to event-based API, temporary breaking tests

---
 examples/unit_test.c |  36 ++++-----
 mongoose.c           | 185 +++++++++++++++++++------------------------
 mongoose.h           |  24 +++---
 3 files changed, 109 insertions(+), 136 deletions(-)

diff --git a/examples/unit_test.c b/examples/unit_test.c
index f5b57d926..6e04248a3 100644
--- a/examples/unit_test.c
+++ b/examples/unit_test.c
@@ -339,20 +339,17 @@ static const char *test_next_option(void) {
   return NULL;
 }
 
-static int cb1(struct mg_connection *conn) {
-  int result = MG_REQUEST_NOT_PROCESSED;
-  if (!strcmp(conn->uri, "/cb1")) {
+static int evh1(struct mg_connection *conn, enum mg_event ev) {
+  if (ev == MG_HTTP_ERROR) {
+    mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
+    return MG_TRUE;
+  } else if (ev == MG_REQ_BEGIN && !strcmp(conn->uri, "/cb1")) {
     mg_printf(conn, "%s %s %s",
               conn->server_param == NULL ? "?" : (char *) conn->server_param,
               conn->connection_param == NULL ? "?" : "!", conn->remote_ip);
-    result = MG_REQUEST_PROCESSED;
+    return MG_TRUE;
   }
-  return result;
-}
-
-static int error_handler(struct mg_connection *conn) {
-  mg_printf(conn, "HTTP/1.0 404 NF\r\n\r\nERR: %d", conn->status_code);
-  return MG_ERROR_PROCESSED;
+  return MG_FALSE;
 }
 
 static int ts1(struct mg_connection *conn) {
@@ -379,16 +376,14 @@ static int ts2(struct mg_connection *conn) {
 
 static const char *test_server(void) {
   char buf1[100] = "", buf2[100] = "";
-  struct mg_server *server = mg_create_server((void *) "foo");
+  struct mg_server *server = mg_create_server((void *) "foo", evh1);
 
   ASSERT(server != NULL);
   ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
   ASSERT(mg_set_option(server, "document_root", ".") == NULL);
-  mg_set_request_handler(server, cb1);
-  mg_set_http_error_handler(server, error_handler);
 
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT),  0, ts1, buf1) == 1);
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, ts2, buf2) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT),  0, buf1) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, buf2) == 1);
 
   { int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
   ASSERT(strcmp(buf1, "foo ? 127.0.0.1") == 0);
@@ -464,15 +459,14 @@ static int cb3(struct mg_connection *conn) {
 
 static const char *test_mg_connect(void) {
   char buf2[40] = "", buf3[40] = "", buf4[40] = "";
-  struct mg_server *server = mg_create_server(NULL);
+  struct mg_server *server = mg_create_server(NULL, NULL);  // cb4h
 
   ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
   ASSERT(mg_set_option(server, "document_root", ".") == NULL);
-  mg_set_request_handler(server, cb4h);
   ASSERT(mg_connect(server, "", 0, 0, NULL, NULL) == 0);
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb2, buf2) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, buf2) == 1);
   ASSERT(mg_connect(server, "127.0.0.1", 29, 0, cb3, buf3) == 1);
-  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, cb4, buf4) == 1);
+  ASSERT(mg_connect(server, "127.0.0.1", atoi(HTTP_PORT), 0, buf4) == 1);
 
   { int i; for (i = 0; i < 50; i++) mg_poll_server(server, 1); }
 
@@ -562,7 +556,7 @@ static const char *test_ssl(void) {
 #endif
 
 static const char *test_mg_set_option(void) {
-  struct mg_server *server = mg_create_server(NULL);
+  struct mg_server *server = mg_create_server(NULL, NULL);
   ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
   ASSERT(mg_get_option(server, "listening_port")[0] != '\0');
   mg_destroy_server(&server);
@@ -571,7 +565,7 @@ static const char *test_mg_set_option(void) {
 
 static const char *test_rewrites(void) {
   char buf1[100] = "xx";
-  struct mg_server *server = mg_create_server(NULL);
+  struct mg_server *server = mg_create_server(NULL, NULL);
 
   ASSERT(mg_set_option(server, "listening_port", "0") == NULL);
   ASSERT(mg_set_option(server, "document_root", ".") == NULL);
diff --git a/mongoose.c b/mongoose.c
index a417be80c..fed4145b4 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -325,14 +325,14 @@ void *ns_start_thread(void *(*f)(void *), void *p) {
 }
 #endif  // NS_DISABLE_THREADS
 
-static void add_connection(struct ns_server *server, struct ns_connection *c) {
+static void ns_add_conn(struct ns_server *server, struct ns_connection *c) {
   c->next = server->active_connections;
   server->active_connections = c;
   c->prev = NULL;
   if (c->next != NULL) c->next->prev = c;
 }
 
-static void remove_connection(struct ns_connection *conn) {
+static void ns_remove_conn(struct ns_connection *conn) {
   if (conn->prev == NULL) conn->server->active_connections = conn->next;
   if (conn->prev) conn->prev->next = conn->next;
   if (conn->next) conn->next->prev = conn->prev;
@@ -341,7 +341,7 @@ static void remove_connection(struct ns_connection *conn) {
 // Print message to buffer. If buffer is large enough to hold the message,
 // return buffer. If buffer is to small, allocate large enough buffer on heap,
 // and return allocated buffer.
-static int alloc_vprintf(char **buf, size_t size, const char *fmt, va_list ap) {
+static int ns_avprintf(char **buf, size_t size, const char *fmt, va_list ap) {
   va_list ap_copy;
   int len;
 
@@ -380,7 +380,7 @@ int ns_vprintf(struct ns_connection *conn, const char *fmt, va_list ap) {
   char mem[2000], *buf = mem;
   int len;
 
-  if ((len = alloc_vprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
+  if ((len = ns_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) {
     iobuf_append(&conn->send_iobuf, buf, len);
   }
   if (buf != mem && buf != NULL) {
@@ -399,14 +399,14 @@ int ns_printf(struct ns_connection *conn, const char *fmt, ...) {
   return len;
 }
 
-static void call_user(struct ns_connection *conn, enum ns_event ev, void *p) {
+static void ns_call(struct ns_connection *conn, enum ns_event ev, void *p) {
   if (conn->server->callback) conn->server->callback(conn, ev, p);
 }
 
-static void close_conn(struct ns_connection *conn) {
+static void ns_close_conn(struct ns_connection *conn) {
   DBG(("%p %d", conn, conn->flags));
-  call_user(conn, NS_CLOSE, NULL);
-  remove_connection(conn);
+  ns_call(conn, NS_CLOSE, NULL);
+  ns_remove_conn(conn);
   closesocket(conn->sock);
   iobuf_free(&conn->recv_iobuf);
   iobuf_free(&conn->send_iobuf);
@@ -421,7 +421,7 @@ void ns_set_close_on_exec(sock_t sock) {
 #endif
 }
 
-static void set_non_blocking_mode(sock_t sock) {
+static void ns_set_non_blocking_mode(sock_t sock) {
 #ifdef _WIN32
   unsigned long on = 1;
   ioctlsocket(sock, FIONBIO, &on);
@@ -467,7 +467,7 @@ int ns_socketpair(sock_t sp[2]) {
 #endif  // NS_DISABLE_SOCKETPAIR
 
 // Valid listening port spec is: [ip_address:]port, e.g. "80", "127.0.0.1:3128"
-static int parse_port_string(const char *str, union socket_address *sa) {
+static int ns_parse_port_string(const char *str, union socket_address *sa) {
   unsigned int a, b, c, d, port;
   int len = 0;
 #ifdef NS_ENABLE_IPV6
@@ -502,7 +502,7 @@ static int parse_port_string(const char *str, union socket_address *sa) {
 }
 
 // 'sa' must be an initialized address to bind to
-static sock_t open_listening_socket(union socket_address *sa) {
+static sock_t ns_open_listening_socket(union socket_address *sa) {
   socklen_t len = sizeof(*sa);
   sock_t on = 1, sock = INVALID_SOCKET;
 
@@ -511,7 +511,7 @@ static sock_t open_listening_socket(union socket_address *sa) {
       !bind(sock, &sa->sa, sa->sa.sa_family == AF_INET ?
             sizeof(sa->sin) : sizeof(sa->sa)) &&
       !listen(sock, SOMAXCONN)) {
-    set_non_blocking_mode(sock);
+    ns_set_non_blocking_mode(sock);
     // In case port was set to 0, get the real port number
     (void) getsockname(sock, &sa->sa, &len);
   } else if (sock != INVALID_SOCKET) {
@@ -541,11 +541,11 @@ int ns_set_ssl_cert(struct ns_server *server, const char *cert) {
 }
 
 int ns_bind(struct ns_server *server, const char *str) {
-  parse_port_string(str, &server->listening_sa);
+  ns_parse_port_string(str, &server->listening_sa);
   if (server->listening_sock != INVALID_SOCKET) {
     closesocket(server->listening_sock);
   }
-  server->listening_sock = open_listening_socket(&server->listening_sa);
+  server->listening_sock = ns_open_listening_socket(&server->listening_sa);
   return server->listening_sock == INVALID_SOCKET ? -1 :
     (int) ntohs(server->listening_sa.sin.sin_port);
 }
@@ -574,13 +574,13 @@ static struct ns_connection *accept_conn(struct ns_server *server) {
 #endif
   } else {
     ns_set_close_on_exec(sock);
-    set_non_blocking_mode(sock);
+    ns_set_non_blocking_mode(sock);
     c->server = server;
     c->sock = sock;
     c->flags |= NSF_ACCEPTED;
 
-    add_connection(server, c);
-    call_user(c, NS_ACCEPT, &sa);
+    ns_add_conn(server, c);
+    ns_call(c, NS_ACCEPT, &sa);
     DBG(("%p %d %p %p", c, c->sock, c->ssl, server->ssl_ctx));
   }
 
@@ -598,8 +598,8 @@ static int ns_is_error(int n) {
 }
 
 #ifdef NS_ENABLE_HEXDUMP
-static void hexdump(const struct ns_connection *conn, const void *buf,
-                    int len, const char *marker) {
+static void ns_hexdump(const struct ns_connection *conn, const void *buf,
+                       int len, const char *marker) {
   const unsigned char *p = (const unsigned char *) buf;
   char path[500], date[100], ascii[17];
   FILE *fp;
@@ -641,7 +641,7 @@ static void hexdump(const struct ns_connection *conn, const void *buf,
 }
 #endif
 
-static void read_from_socket(struct ns_connection *conn) {
+static void ns_read_from_socket(struct ns_connection *conn) {
   char buf[2048];
   int n = 0;
 
@@ -671,7 +671,7 @@ static void read_from_socket(struct ns_connection *conn) {
     if (ok != 0) {
       conn->flags |= NSF_CLOSE_IMMEDIATELY;
     }
-    call_user(conn, NS_CONNECT, &ok);
+    ns_call(conn, NS_CONNECT, &ok);
     return;
   }
 
@@ -692,7 +692,7 @@ static void read_from_socket(struct ns_connection *conn) {
   }
 
 #ifdef NS_ENABLE_HEXDUMP
-  hexdump(conn, buf, n, "<-");
+  ns_hexdump(conn, buf, n, "<-");
 #endif
 
   DBG(("%p <- %d bytes [%.*s%s]",
@@ -702,11 +702,11 @@ static void read_from_socket(struct ns_connection *conn) {
     conn->flags |= NSF_CLOSE_IMMEDIATELY;
   } else if (n > 0) {
     iobuf_append(&conn->recv_iobuf, buf, n);
-    call_user(conn, NS_RECV, &n);
+    ns_call(conn, NS_RECV, &n);
   }
 }
 
-static void write_to_socket(struct ns_connection *conn) {
+static void ns_write_to_socket(struct ns_connection *conn) {
   struct iobuf *io = &conn->send_iobuf;
   int n = 0;
 
@@ -719,7 +719,7 @@ static void write_to_socket(struct ns_connection *conn) {
 
 
 #ifdef NS_ENABLE_HEXDUMP
-  hexdump(conn, io->buf, n, "->");
+  ns_hexdump(conn, io->buf, n, "->");
 #endif
 
   DBG(("%p -> %d bytes [%.*s%s]", conn, n, io->len < 40 ? io->len : 40,
@@ -736,14 +736,14 @@ static void write_to_socket(struct ns_connection *conn) {
     conn->flags |= NSF_CLOSE_IMMEDIATELY;
   }
 
-  call_user(conn, NS_SEND, NULL);
+  ns_call(conn, NS_SEND, NULL);
 }
 
 int ns_send(struct ns_connection *conn, const void *buf, int len) {
   return iobuf_append(&conn->send_iobuf, buf, len);
 }
 
-static void add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
+static void ns_add_to_set(sock_t sock, fd_set *set, sock_t *max_fd) {
   if (sock != INVALID_SOCKET) {
     FD_SET(sock, set);
     if (*max_fd == INVALID_SOCKET || sock > *max_fd) {
@@ -765,19 +765,19 @@ int ns_server_poll(struct ns_server *server, int milli) {
 
   FD_ZERO(&read_set);
   FD_ZERO(&write_set);
-  add_to_set(server->listening_sock, &read_set, &max_fd);
+  ns_add_to_set(server->listening_sock, &read_set, &max_fd);
 
   for (conn = server->active_connections; conn != NULL; conn = tmp_conn) {
     tmp_conn = conn->next;
-    call_user(conn, NS_POLL, &current_time);
-    add_to_set(conn->sock, &read_set, &max_fd);
+    ns_call(conn, NS_POLL, &current_time);
+    ns_add_to_set(conn->sock, &read_set, &max_fd);
     if (conn->flags & NSF_CONNECTING) {
-      add_to_set(conn->sock, &write_set, &max_fd);
+      ns_add_to_set(conn->sock, &write_set, &max_fd);
     }
     if (conn->send_iobuf.len > 0 && !(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
-      add_to_set(conn->sock, &write_set, &max_fd);
+      ns_add_to_set(conn->sock, &write_set, &max_fd);
     } else if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
-      close_conn(conn);
+      ns_close_conn(conn);
     }
   }
 
@@ -786,7 +786,7 @@ int ns_server_poll(struct ns_server *server, int milli) {
 
   if (select((int) max_fd + 1, &read_set, &write_set, NULL, &tv) > 0) {
     // Accept new connections
-    if (server->listening_sock >= 0 &&
+    if (server->listening_sock != INVALID_SOCKET &&
         FD_ISSET(server->listening_sock, &read_set)) {
       // We're not looping here, and accepting just one connection at
       // a time. The reason is that eCos does not respect non-blocking
@@ -800,14 +800,14 @@ int ns_server_poll(struct ns_server *server, int milli) {
       tmp_conn = conn->next;
       if (FD_ISSET(conn->sock, &read_set)) {
         conn->last_io_time = current_time;
-        read_from_socket(conn);
+        ns_read_from_socket(conn);
       }
       if (FD_ISSET(conn->sock, &write_set)) {
         if (conn->flags & NSF_CONNECTING) {
-          read_from_socket(conn);
+          ns_read_from_socket(conn);
         } else if (!(conn->flags & NSF_BUFFER_BUT_DONT_SEND)) {
           conn->last_io_time = current_time;
-          write_to_socket(conn);
+          ns_write_to_socket(conn);
         }
       }
     }
@@ -817,7 +817,7 @@ int ns_server_poll(struct ns_server *server, int milli) {
     tmp_conn = conn->next;
     num_active_connections++;
     if (conn->flags & NSF_CLOSE_IMMEDIATELY) {
-      close_conn(conn);
+      ns_close_conn(conn);
     }
   }
   //DBG(("%d active connections", num_active_connections));
@@ -846,7 +846,7 @@ struct ns_connection *ns_connect(struct ns_server *server, const char *host,
   sin.sin_family = AF_INET;
   sin.sin_port = htons((uint16_t) port);
   sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
-  set_non_blocking_mode(sock);
+  ns_set_non_blocking_mode(sock);
 
   connect_ret_val = connect(sock, (struct sockaddr *) &sin, sizeof(sin));
   if (ns_is_error(connect_ret_val)) {
@@ -871,7 +871,7 @@ struct ns_connection *ns_connect(struct ns_server *server, const char *host,
   }
 #endif
 
-  add_connection(server, conn);
+  ns_add_conn(server, conn);
   DBG(("%p %s:%d %d %p", conn, host, port, conn->sock, conn->ssl));
 
   return conn;
@@ -881,12 +881,12 @@ struct ns_connection *ns_add_sock(struct ns_server *s, sock_t sock, void *p) {
   struct ns_connection *conn;
   if ((conn = (struct ns_connection *) NS_MALLOC(sizeof(*conn))) != NULL) {
     memset(conn, 0, sizeof(*conn));
-    set_non_blocking_mode(sock);
+    ns_set_non_blocking_mode(sock);
     conn->sock = sock;
     conn->connection_data = p;
     conn->server = s;
     conn->last_io_time = time(NULL);
-    add_connection(s, conn);
+    ns_add_conn(s, conn);
     DBG(("%p %d", conn, sock));
   }
   return conn;
@@ -935,7 +935,7 @@ void ns_server_free(struct ns_server *s) {
 
   for (conn = s->active_connections; conn != NULL; conn = tmp_conn) {
     tmp_conn = conn->next;
-    close_conn(conn);
+    ns_close_conn(conn);
   }
 
 #ifndef NS_DISABLE_SOCKETPAIR
@@ -1122,10 +1122,7 @@ static const char *static_config_options[] = {
 struct mg_server {
   struct ns_server ns_server;
   union socket_address lsa;   // Listening socket address
-  mg_handler_t request_handler;
-  mg_handler_t http_close_handler;
-  mg_handler_t error_handler;
-  mg_handler_t auth_handler;
+  mg_handler_t event_handler;
   char *config_options[NUM_OPTIONS];
   char local_ip[48];
 };
@@ -1155,7 +1152,7 @@ struct connection {
   int64_t cl;             // Reply content length, for Range support
   int request_len;  // Request length, including last \r\n after last header
   //int flags;        // CONN_* flags: CONN_CLOSE, CONN_SPOOL_DONE, etc
-  mg_handler_t handler;  // Callback for HTTP client
+  //mg_handler_t handler;  // Callback for HTTP client
 };
 
 #define MG_CONN_2_CONN(c) ((struct connection *) ((char *) (c) - \
@@ -1433,6 +1430,12 @@ static const char *status_code_to_str(int status_code) {
   }
 }
 
+static int call_user(struct connection *conn, enum mg_event ev) {
+  return conn != NULL && conn->server != NULL &&
+    conn->server->event_handler != NULL ?
+    conn->server->event_handler(&conn->mg_conn, ev) : MG_FALSE;
+}
+
 static void send_http_error(struct connection *conn, int code,
                             const char *fmt, ...) {
   const char *message = status_code_to_str(code);
@@ -1445,8 +1448,7 @@ static void send_http_error(struct connection *conn, int code,
   conn->mg_conn.status_code = code;
 
   // Invoke error handler if it is set
-  if (conn->server->error_handler != NULL &&
-      conn->server->error_handler(&conn->mg_conn) == MG_ERROR_PROCESSED) {
+  if (call_user(conn, MG_HTTP_ERROR) == MG_TRUE) {
     close_local_endpoint(conn);
     return;
   }
@@ -2505,7 +2507,7 @@ static int deliver_websocket_frame(struct connection *conn) {
     }
 
     // Call the handler and remove frame from the iobuf
-    if (conn->server->request_handler(&conn->mg_conn) == MG_CLIENT_CLOSE) {
+    if (call_user(conn, MG_REQ_BEGIN) == MG_FALSE) {
       conn->ns_conn->flags |= NSF_FINISHED_SENDING_DATA;
     }
     iobuf_remove(&conn->ns_conn->recv_iobuf, frame_len);
@@ -2581,15 +2583,11 @@ static void write_terminating_chunk(struct connection *conn) {
 static int call_request_handler(struct connection *conn) {
   int result;
   conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
-  switch ((result = conn->server->request_handler(&conn->mg_conn))) {
-    case MG_REQUEST_CALL_AGAIN: conn->ns_conn->flags |= MG_LONG_RUNNING; break;
-    case MG_REQUEST_NOT_PROCESSED: break;
-    default:
-      if (conn->ns_conn->flags & MG_HEADERS_SENT) {
-        write_terminating_chunk(conn);
-      }
-      close_local_endpoint(conn);
-      break;
+  if ((result = call_user(conn, MG_REQ_BEGIN)) == MG_TRUE) {
+    if (conn->ns_conn->flags & MG_HEADERS_SENT) {
+      write_terminating_chunk(conn);
+    }
+    close_local_endpoint(conn);
   }
   return result;
 }
@@ -3554,8 +3552,7 @@ static int check_password(const char *method, const char *ha1, const char *uri,
   mg_md5(expected_response, ha1, ":", nonce, ":", nc,
       ":", cnonce, ":", qop, ":", ha2, NULL);
 
-  return mg_strcasecmp(response, expected_response) == 0 ?
-    MG_AUTH_OK : MG_AUTH_FAIL;
+  return mg_strcasecmp(response, expected_response) == 0 ? MG_TRUE : MG_FALSE;
 }
 
 
@@ -3585,14 +3582,14 @@ int mg_authorize_digest(struct mg_connection *c, FILE *fp) {
       return check_password(c->request_method, ha1, uri,
                             nonce, nc, cnonce, qop, resp);
   }
-  return MG_AUTH_FAIL;
+  return MG_FALSE;
 }
 
 
 // Return 1 if request is authorised, 0 otherwise.
 static int is_authorized(struct connection *conn, const char *path) {
   FILE *fp;
-  int authorized = MG_AUTH_OK;
+  int authorized = MG_TRUE;
 
   if ((fp = open_auth_file(conn, path)) != NULL) {
     authorized = mg_authorize_digest(&conn->mg_conn, fp);
@@ -3605,7 +3602,7 @@ static int is_authorized(struct connection *conn, const char *path) {
 static int is_authorized_for_dav(struct connection *conn) {
   const char *auth_file = conn->server->config_options[DAV_AUTH_FILE];
   FILE *fp;
-  int authorized = MG_AUTH_FAIL;
+  int authorized = MG_FALSE;
 
   if (auth_file != NULL && (fp = fopen(auth_file, "r")) != NULL) {
     authorized = mg_authorize_digest(&conn->mg_conn, fp);
@@ -3952,16 +3949,14 @@ static void open_local_endpoint(struct connection *conn, int skip_user) {
 #endif
 
 #ifndef MONGOOSE_NO_AUTH
-  // Call auth handler
-  if (conn->server->auth_handler != NULL &&
-      conn->server->auth_handler(&conn->mg_conn) == MG_AUTH_FAIL) {
+  if (conn->server->event_handler && call_user(conn, MG_AUTH) == MG_FALSE) {
     mg_send_digest_auth_request(&conn->mg_conn);
     return;
   }
 #endif
 
   // Call URI handler if one is registered for this URI
-  if (skip_user == 0 && conn->server->request_handler != NULL) {
+  if (skip_user == 0 && conn->server->event_handler != NULL) {
     conn->endpoint_type = EP_USER;
 #if MONGOOSE_POST_SIZE_LIMIT > 1
     {
@@ -4130,7 +4125,7 @@ static void call_http_client_handler(struct connection *conn, int code) {
     conn->mg_conn.content_len = conn->ns_conn->recv_iobuf.len;
   }
   conn->mg_conn.content = conn->ns_conn->recv_iobuf.buf;
-  if (conn->handler(&conn->mg_conn) || code == MG_CONNECT_FAILURE ||
+  if (call_user(conn, -1) || code == MG_CONNECT_FAILURE ||
       code == MG_DOWNLOAD_FAILURE) {
     conn->ns_conn->flags |= NSF_CLOSE_IMMEDIATELY;
   }
@@ -4156,12 +4151,12 @@ static void process_response(struct connection *conn) {
   }
 }
 
-int mg_connect(struct mg_server *server, const char *host, int port,
-               int use_ssl, mg_handler_t handler, void *param) {
+struct mg_connection *mg_connect(struct mg_server *server, const char *host,
+                                 int port, int use_ssl) {
   struct ns_connection *nsconn;
   struct connection *conn;
 
-  nsconn = ns_connect(&server->ns_server, host, port, use_ssl, param);
+  nsconn = ns_connect(&server->ns_server, host, port, use_ssl, NULL);
   if (nsconn == NULL) return 0;
 
   if ((conn = (struct connection *) calloc(1, sizeof(*conn))) == NULL) {
@@ -4175,14 +4170,13 @@ int mg_connect(struct mg_server *server, const char *host, int port,
 
   conn->server = server;
   conn->endpoint_type = EP_CLIENT;
-  conn->handler = handler;
+  //conn->handler = handler;
   conn->mg_conn.server_param = server->ns_server.server_data;
-  conn->mg_conn.connection_param = param;
   conn->birth_time = time(NULL);
   conn->ns_conn->flags = NSF_CONNECTING;
   conn->mg_conn.status_code = MG_CONNECT_FAILURE;
 
-  return 1;
+  return &conn->mg_conn;
 }
 
 #ifndef MONGOOSE_NO_LOGGING
@@ -4311,21 +4305,20 @@ struct mg_iterator {
   mg_handler_t cb;
   void *param;
 };
+union variant { mg_handler_t cb; void *p; };
 
 static void iter(struct ns_connection *nsconn, enum ns_event ev, void *param) {
   if (ev == NS_POLL) {
-    struct mg_iterator *it = (struct mg_iterator *) param;
+    union variant *variant = (union variant *) param;
     struct connection *c = (struct connection *) nsconn->connection_data;
-    c->mg_conn.callback_param = it->param;
-    it->cb(&c->mg_conn);
+    variant->cb(&c->mg_conn, MG_POLL);
   }
 }
 
 // Apply function to all active connections.
-void mg_iterate_over_connections(struct mg_server *server, mg_handler_t handler,
-                                 void *param) {
-  struct mg_iterator it = { handler, param };
-  ns_iterate(&server->ns_server, iter, &it);
+void mg_iterate_over_connections(struct mg_server *server, mg_handler_t cb) {
+  union variant variant = { cb };
+  ns_iterate(&server->ns_server, iter, &variant);
 }
 
 static int get_var(const char *data, size_t data_len, const char *name,
@@ -4550,7 +4543,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
         int ok = * (int *) p;
         conn->mg_conn.status_code = ok == 0 ?
           MG_CONNECT_SUCCESS : MG_CONNECT_FAILURE;
-        if (conn->handler(&conn->mg_conn) != 0 || ok != 0) {
+        if (call_user(conn, MG_CONNECT) != 0 || ok != 0) {
           nc->flags |= NSF_CLOSE_IMMEDIATELY;
         }
       }
@@ -4585,10 +4578,7 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
           call_http_client_handler(conn, MG_DOWNLOAD_SUCCESS);
         }
 
-        if (conn->server->http_close_handler) {
-          conn->server->http_close_handler(&conn->mg_conn);
-        }
-
+        call_user(conn, MG_CLOSE);
         close_local_endpoint(conn);
         free(conn);
       }
@@ -4619,22 +4609,6 @@ static void mg_ev_handler(struct ns_connection *nc, enum ns_event ev, void *p) {
   }
 }
 
-void mg_set_request_handler(struct mg_server *server, mg_handler_t handler) {
-  server->request_handler = handler;
-}
-
-void mg_set_http_close_handler(struct mg_server *server, mg_handler_t handler) {
-  server->http_close_handler = handler;
-}
-
-void mg_set_http_error_handler(struct mg_server *server, mg_handler_t handler) {
-  server->error_handler = handler;
-}
-
-void mg_set_auth_handler(struct mg_server *server, mg_handler_t handler) {
-  server->auth_handler = handler;
-}
-
 void mg_set_listening_socket(struct mg_server *server, int sock) {
   if (server->ns_server.listening_sock != INVALID_SOCKET) {
     closesocket(server->ns_server.listening_sock);
@@ -4652,9 +4626,10 @@ const char *mg_get_option(const struct mg_server *server, const char *name) {
   return i == -1 ? NULL : opts[i] == NULL ? "" : opts[i];
 }
 
-struct mg_server *mg_create_server(void *server_data) {
+struct mg_server *mg_create_server(void *server_data, mg_handler_t handler) {
   struct mg_server *server = (struct mg_server *) calloc(1, sizeof(*server));
   ns_server_init(&server->ns_server, server_data, mg_ev_handler);
   set_default_option_values(server->config_options);
+  server->event_handler = handler;
   return server;
 }
diff --git a/mongoose.h b/mongoose.h
index 5748a906a..4426cac6f 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -55,26 +55,31 @@ struct mg_connection {
   int wsbits;                 // First byte of the websocket frame
   void *server_param;         // Parameter passed to mg_add_uri_handler()
   void *connection_param;     // Placeholder for connection-specific data
-  void *callback_param;       // Used by mg_iterate_over_connections()
 };
 
 struct mg_server; // Opaque structure describing server instance
-typedef int (*mg_handler_t)(struct mg_connection *);
+enum mg_result { MG_FALSE, MG_TRUE };
+enum mg_event {
+  MG_POLL,        // Callback return value is ignored
+  MG_AUTH,        // If callback returns MG_FALSE, authentication fails
+  MG_REQ_BEGIN,   // If callback returns MG_FALSE, Mongoose continues with req
+  MG_REQ_END,     // Callback return value is ignored
+  MG_CLOSE,       // Connection is closed
+  MG_CONNECT,     // If callback returns MG_FALSE, connect fails
+  MG_HTTP_ERROR   // If callback returns MG_FALSE, Mongoose continues with err
+};
+typedef int (*mg_handler_t)(struct mg_connection *, enum mg_event);
 
 // Server management functions
-struct mg_server *mg_create_server(void *server_param);
+struct mg_server *mg_create_server(void *server_param, mg_handler_t handler);
 void mg_destroy_server(struct mg_server **);
 const char *mg_set_option(struct mg_server *, const char *opt, const char *val);
 int mg_poll_server(struct mg_server *, int milliseconds);
-void mg_set_request_handler(struct mg_server *, mg_handler_t);
-void mg_set_http_close_handler(struct mg_server *, mg_handler_t);
-void mg_set_http_error_handler(struct mg_server *, mg_handler_t);
-void mg_set_auth_handler(struct mg_server *, mg_handler_t);
 const char **mg_get_valid_option_names(void);
 const char *mg_get_option(const struct mg_server *server, const char *name);
 void mg_set_listening_socket(struct mg_server *, int sock);
 int mg_get_listening_socket(struct mg_server *);
-void mg_iterate_over_connections(struct mg_server *, mg_handler_t, void *);
+void mg_iterate_over_connections(struct mg_server *, mg_handler_t);
 
 // Connection management functions
 void mg_send_status(struct mg_connection *, int status_code);
@@ -115,8 +120,7 @@ enum {
   MG_CONNECT_SUCCESS, MG_CONNECT_FAILURE,
   MG_DOWNLOAD_SUCCESS, MG_DOWNLOAD_FAILURE
 };
-int mg_connect(struct mg_server *, const char *host, int port, int use_ssl,
-               mg_handler_t handler, void *param);
+struct mg_connection *mg_connect(struct mg_server *, const char *, int, int);
 
 #ifdef __cplusplus
 }
-- 
GitLab