From b7adf9b52ab48b9b516ffc5ae98b717d7e7c7b17 Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Fri, 20 Dec 2013 09:44:51 +0000
Subject: [PATCH] Passing server_param to the URI callback

---
 build/test/unit_test.c | 71 +++++++++++++++++++++++++++++++-----------
 mongoose.c             |  4 +++
 2 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/build/test/unit_test.c b/build/test/unit_test.c
index 0fc7198c7..a7ac616ba 100644
--- a/build/test/unit_test.c
+++ b/build/test/unit_test.c
@@ -28,7 +28,6 @@
 
 static int static_num_tests = 0;
 
-#if 0
 // Connects to host:port, and sends formatted request to it. Returns
 // malloc-ed reply and reply length, or NULL on error. Reply contains
 // everything including headers, not just the message body.
@@ -39,8 +38,8 @@ static char *wget(const char *host, int port, int *len, const char *fmt, ...) {
   struct hostent *he = NULL;
   va_list ap;
 
-  if (host != NULL ||
-      (he = gethostbyname(host)) != NULL ||
+  if (host != NULL &&
+      (he = gethostbyname(host)) != NULL &&
       (sock = socket(PF_INET, SOCK_STREAM, 0)) != -1) {
     sin.sin_family = AF_INET;
     sin.sin_port = htons((uint16_t) port);
@@ -57,7 +56,7 @@ static char *wget(const char *host, int port, int *len, const char *fmt, ...) {
       if (request_len == 0) {
         *len = 0;
         while ((n = recv(sock, buf, sizeof(buf), 0)) > 0) {
-          if (*len + n < reply_size) {
+          if (*len + n > reply_size) {
             reply = realloc(reply, reply_size + sizeof(buf)); // Leak possible
             reply_size += sizeof(buf);
           }
@@ -86,7 +85,6 @@ static char *read_file(const char *path, int *size) {
   }
   return data;
 }
-#endif
 
 static const char *test_parse_http_message() {
   struct mg_connection ri;
@@ -360,16 +358,19 @@ static const char *test_next_option(void) {
   return NULL;
 }
 
-#if 0
 static int cb1(struct mg_connection *conn) {
-  assert(conn != NULL);
-  assert(conn->server_param != NULL);
-  assert(conn->connection_param == NULL);
-  assert(strcmp((char *) conn->server_param, "foo") == 0);
+  char buf[100];
+
+  // We're not sending HTTP headers here, to make testing easier
+  snprintf(buf, sizeof(buf), "%s %s",
+           conn->server_param == NULL ? "?" : (char *) conn->server_param,
+           conn->connection_param == NULL ? "?" : "!");
+  mg_write(conn, buf, strlen(buf));
+
   return 1;
 }
 
-static const char *test_requests(struct mg_server *server) {
+static const char *test_regular_file(void) {
   static const char *fname = "main.c";
   int reply_len, file_len;
   char *reply, *file_data;
@@ -381,25 +382,57 @@ static const char *test_requests(struct mg_server *server) {
   ASSERT((file_data = read_file(fname, &file_len)) != NULL);
   ASSERT(file_len == st.st_size);
 
-  mg_poll_server(server, 0);
+  reply = wget("127.0.0.1", atoi(HTTP_PORT), &reply_len,
+               "GET /%s.c HTTP/1.0\r\n\r\n", fname);
+  ASSERT(reply != NULL);
+  ASSERT(reply_len > 0);
+  // TODO(lsm): test headers and content
+
+  free(reply);
+  free(file_data);
+
+  return NULL;
+}
+
+static const char *test_server_param(void) {
+  int reply_len;
+  char *reply;
+
+  reply = wget("127.0.0.1", atoi(HTTP_PORT), &reply_len, "%s",
+               "GET /cb1 HTTP/1.0\r\n\r\n");
+  ASSERT(reply != NULL);
+  ASSERT(reply_len == 5);
+  ASSERT(memcmp(reply, "foo ?", 5) == 0);  // cb1() does not send HTTP headers
+  printf("%d [%.*s]\n", reply_len, reply_len, reply);
+  free(reply);
+
+  return NULL;
+}
+
+static void *server_thread(void *param) {
+  int i;
+  for (i = 0; i < 10; i++) mg_poll_server((struct mg_server *) param, 1);
   return NULL;
 }
 
 static const char *test_server(void) {
   struct mg_server *server = mg_create_server("foo");
+
   ASSERT(server != NULL);
   ASSERT(mg_set_option(server, "listening_port", LISTENING_ADDR) == NULL);
-  ASSERT(mg_set_option(server, "document_root", "..") == NULL);
+  ASSERT(mg_set_option(server, "document_root", ".") == NULL);
   mg_add_uri_handler(server, "/cb1", cb1);
-  do {
-    const char *msg = test_requests(server);
-    if (msg) return msg;
-  } while (0);
+  mg_start_thread(server_thread, server);
+  RUN_TEST(test_regular_file);
+  RUN_TEST(test_server_param);
+
+  // TODO(lsm): come up with a better way of thread sync
+  sleep(1);
+
   mg_destroy_server(&server);
   ASSERT(server == NULL);
   return NULL;
 }
-#endif
 
 static const char *run_all_tests(void) {
   RUN_TEST(test_should_keep_alive);
@@ -413,7 +446,7 @@ static const char *run_all_tests(void) {
   RUN_TEST(test_mg_parse_header);
   RUN_TEST(test_get_var);
   RUN_TEST(test_next_option);
-  //RUN_TEST(test_server);
+  RUN_TEST(test_server);
   return NULL;
 }
 
diff --git a/mongoose.c b/mongoose.c
index 1680bde5b..2d5dd395a 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -1746,6 +1746,10 @@ static void call_uri_handler_if_data_is_buffered(struct connection *conn) {
   struct iobuf *loc = &conn->local_iobuf;
   struct mg_connection *c = &conn->mg_conn;
 
+  // Header parsing does memset() on the whole mg_connection, nullifying
+  // connection_param and server_param. Set them just before calling back.
+  c->server_param = conn->server->server_data;
+
   c->content = loc->buf;
 #ifndef NO_WEBSOCKET
   if (conn->mg_conn.is_websocket) {
-- 
GitLab