From aa59dda96632c22e1b70017905a0f990db09ba1c Mon Sep 17 00:00:00 2001
From: Sergey Lyubka <valenok@gmail.com>
Date: Thu, 9 Jan 2014 17:50:57 +0000
Subject: [PATCH] wrapped read_from_cgi() into NO_CGI

---
 mongoose.c | 229 +++++++++++++++++++++++++++--------------------------
 1 file changed, 115 insertions(+), 114 deletions(-)

diff --git a/mongoose.c b/mongoose.c
index 3c1deb5e7..ec09ed8e5 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -516,6 +516,63 @@ static int mg_snprintf(char *buf, size_t buflen, const char *fmt, ...) {
   return n;
 }
 
+// Check whether full request is buffered. Return:
+//   -1  if request is malformed
+//    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) {
+  const unsigned char *buf = (unsigned char *) s;
+  int i;
+
+  for (i = 0; i < buf_len; i++) {
+    // Control characters are not allowed but >=128 are.
+    // Abort scan as soon as one malformed character is found.
+    if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
+      return -1;
+    } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
+      return i + 2;
+    } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
+               buf[i + 2] == '\n') {
+      return i + 3;
+    }
+  }
+
+  return 0;
+}
+
+// Skip the characters until one of the delimiters characters found.
+// 0-terminate resulting word. Skip the rest of the delimiters if any.
+// Advance pointer to buffer to the next word. Return found 0-terminated word.
+static char *skip(char **buf, const char *delimiters) {
+  char *p, *begin_word, *end_word, *end_delimiters;
+
+  begin_word = *buf;
+  end_word = begin_word + strcspn(begin_word, delimiters);
+  end_delimiters = end_word + strspn(end_word, delimiters);
+
+  for (p = end_word; p < end_delimiters; p++) {
+    *p = '\0';
+  }
+
+  *buf = end_delimiters;
+
+  return begin_word;
+}
+
+// Parse HTTP headers from the given buffer, advance buffer to the point
+// where parsing stopped.
+static void parse_http_headers(char **buf, struct mg_connection *ri) {
+  size_t i;
+
+  for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
+    ri->http_headers[i].name = skip(buf, ": ");
+    ri->http_headers[i].value = skip(buf, "\r\n");
+    if (ri->http_headers[i].name[0] == '\0')
+      break;
+    ri->num_headers = i + 1;
+  }
+}
+
 static const char *status_code_to_str(int status_code) {
   switch (status_code) {
     case 200: return "OK";
@@ -677,6 +734,10 @@ static int mg_socketpair(sock_t sp[2]) {
   return ret;
 }
 
+static int is_error(int n) {
+  return n == 0 || (n < 0 && errno != EINTR && errno != EAGAIN);
+}
+
 #ifndef NO_CGI
 #ifdef _WIN32
 static pid_t start_process(char *interp, const char *cmd, const char *env,
@@ -941,6 +1002,58 @@ static void open_cgi_endpoint(struct connection *conn, const char *prog) {
 
   closesocket(fds[1]);
 }
+
+static void read_from_cgi(struct connection *conn) {
+  char buf[IOBUF_SIZE];
+  int len, n = recv(conn->endpoint.cgi_sock, buf, sizeof(buf), 0);
+
+  DBG(("%p %d", conn, n));
+  if (is_error(n)) {
+    close_local_endpoint(conn);
+  } else if (n > 0) {
+    if (conn->num_bytes_sent == 0 && conn->remote_iobuf.len == 0) {
+      // Parse CGI headers, and modify the reply line if needed
+      if ((len = get_request_len(buf, n)) > 0) {
+        const char *status = NULL;
+        char *s = buf, buf2[sizeof(buf)];
+        struct mg_connection c;
+        int i, k;
+
+        memset(&c, 0, sizeof(c));
+        buf[len - 1] = '\0';
+        parse_http_headers(&s, &c);
+        if (mg_get_header(&c, "Location") != NULL) {
+          status = "302 Moved";
+        } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) {
+          status = "200 OK";
+        }
+        k = mg_snprintf(buf2, sizeof(buf2), "HTTP/1.1 %s\r\n", status);
+        spool(&conn->remote_iobuf, buf2, k);
+        for (i = 0; i < c.num_headers; i++) {
+          k = mg_snprintf(buf2, sizeof(buf2), "%s: %s\r\n",
+                          c.http_headers[i].name, c.http_headers[i].value);
+          spool(&conn->remote_iobuf, buf2, k);
+        }
+        spool(&conn->remote_iobuf, "\r\n", 2);
+        memmove(buf, buf + len, n - len);
+        n -= len;
+      } else {
+        static const char ok_200[] = "HTTP/1.1 200 OK\r\n";
+        spool(&conn->remote_iobuf, ok_200, sizeof(ok_200) - 1);
+      }
+    }
+    spool(&conn->remote_iobuf, buf, n);
+  }
+}
+
+static void forward_post_data(struct connection *conn) {
+  struct iobuf *io = &conn->local_iobuf;
+  int n = send(conn->endpoint.cgi_sock, io->buf, io->len, 0);
+  if (n > 0) {
+    memmove(io->buf, io->buf + n, io->len - n);
+    io->len -= n;
+  }
+}
 #endif  // !NO_CGI
 
 // 'sa' must be an initialized address to bind to
@@ -1079,50 +1192,6 @@ static void close_conn(struct connection *conn) {
   free(conn);
 }
 
-// Check whether full request is buffered. Return:
-//   -1  if request is malformed
-//    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) {
-  const unsigned char *buf = (unsigned char *) s;
-  int i;
-
-  for (i = 0; i < buf_len; i++) {
-    // Control characters are not allowed but >=128 are.
-    // Abort scan as soon as one malformed character is found.
-    if (!isprint(buf[i]) && buf[i] != '\r' && buf[i] != '\n' && buf[i] < 128) {
-      return -1;
-    } else if (buf[i] == '\n' && i + 1 < buf_len && buf[i + 1] == '\n') {
-      return i + 2;
-    } else if (buf[i] == '\n' && i + 2 < buf_len && buf[i + 1] == '\r' &&
-               buf[i + 2] == '\n') {
-      return i + 3;
-    }
-  }
-
-  return 0;
-}
-
-
-// Skip the characters until one of the delimiters characters found.
-// 0-terminate resulting word. Skip the rest of the delimiters if any.
-// Advance pointer to buffer to the next word. Return found 0-terminated word.
-static char *skip(char **buf, const char *delimiters) {
-  char *p, *begin_word, *end_word, *end_delimiters;
-
-  begin_word = *buf;
-  end_word = begin_word + strcspn(begin_word, delimiters);
-  end_delimiters = end_word + strspn(end_word, delimiters);
-
-  for (p = end_word; p < end_delimiters; p++) {
-    *p = '\0';
-  }
-
-  *buf = end_delimiters;
-
-  return begin_word;
-}
-
 // Protect against directory disclosure attack by removing '..',
 // excessive '/' and '\' characters
 static void remove_double_dots_and_double_slashes(char *s) {
@@ -1167,20 +1236,6 @@ int mg_url_decode(const char *src, int src_len, char *dst,
   return i >= src_len ? j : -1;
 }
 
-// Parse HTTP headers from the given buffer, advance buffer to the point
-// where parsing stopped.
-static void parse_http_headers(char **buf, struct mg_connection *ri) {
-  size_t i;
-
-  for (i = 0; i < ARRAY_SIZE(ri->http_headers); i++) {
-    ri->http_headers[i].name = skip(buf, ": ");
-    ri->http_headers[i].value = skip(buf, "\r\n");
-    if (ri->http_headers[i].name[0] == '\0')
-      break;
-    ri->num_headers = i + 1;
-  }
-}
-
 static int is_valid_http_method(const char *method) {
   return !strcmp(method, "GET") || !strcmp(method, "POST") ||
     !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
@@ -1688,10 +1743,6 @@ static void ping_idle_websocket_connection(struct connection *conn, time_t t) {
 #define ping_idle_websocket_connection(conn, t)
 #endif // !NO_WEBSOCKET
 
-static int is_error(int n) {
-  return n == 0 || (n < 0 && errno != EINTR && errno != EAGAIN);
-}
-
 static void write_to_client(struct connection *conn) {
   struct iobuf *io = &conn->remote_iobuf;
   int n = conn->ssl == NULL ? send(conn->client_sock, io->buf, io->len, 0) :
@@ -3183,15 +3234,6 @@ static void send_continue_if_expected(struct connection *conn) {
   }
 }
 
-static void forward_post_data(struct connection *conn) {
-  struct iobuf *io = &conn->local_iobuf;
-  int n = send(conn->endpoint.cgi_sock, io->buf, io->len, 0);
-  if (n > 0) {
-    memmove(io->buf, io->buf + n, io->len - n);
-    io->len -= n;
-  }
-}
-
 static int is_valid_uri(const char *uri) {
   // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
   // URI can be an asterisk (*) or should start with slash.
@@ -3275,49 +3317,6 @@ static void read_from_client(struct connection *conn) {
   }
 }
 
-static void read_from_cgi(struct connection *conn) {
-  char buf[IOBUF_SIZE];
-  int len, n = recv(conn->endpoint.cgi_sock, buf, sizeof(buf), 0);
-
-  DBG(("%p %d", conn, n));
-  if (is_error(n)) {
-    close_local_endpoint(conn);
-  } else if (n > 0) {
-    if (conn->num_bytes_sent == 0 && conn->remote_iobuf.len == 0) {
-      // Parse CGI headers, and modify the reply line if needed
-      if ((len = get_request_len(buf, n)) > 0) {
-        const char *status = NULL;
-        char *s = buf, buf2[sizeof(buf)];
-        struct mg_connection c;
-        int i, k;
-
-        memset(&c, 0, sizeof(c));
-        buf[len - 1] = '\0';
-        parse_http_headers(&s, &c);
-        if (mg_get_header(&c, "Location") != NULL) {
-          status = "302 Moved";
-        } else if ((status = (char *) mg_get_header(&c, "Status")) == NULL) {
-          status = "200 OK";
-        }
-        k = mg_snprintf(buf2, sizeof(buf2), "HTTP/1.1 %s\r\n", status);
-        spool(&conn->remote_iobuf, buf2, k);
-        for (i = 0; i < c.num_headers; i++) {
-          k = mg_snprintf(buf2, sizeof(buf2), "%s: %s\r\n",
-                          c.http_headers[i].name, c.http_headers[i].value);
-          spool(&conn->remote_iobuf, buf2, k);
-        }
-        spool(&conn->remote_iobuf, "\r\n", 2);
-        memmove(buf, buf + len, n - len);
-        n -= len;
-      } else {
-        static const char ok_200[] = "HTTP/1.1 200 OK\r\n";
-        spool(&conn->remote_iobuf, ok_200, sizeof(ok_200) - 1);
-      }
-    }
-    spool(&conn->remote_iobuf, buf, n);
-  }
-}
-
 #ifndef NO_LOGGING
 static void log_header(const struct mg_connection *conn, const char *header,
                        FILE *fp) {
@@ -3475,10 +3474,12 @@ unsigned int mg_poll_server(struct mg_server *server, int milliseconds) {
         conn->last_activity_time = current_time;
         read_from_client(conn);
       }
+#ifndef NO_CGI
       if (conn->endpoint_type == EP_CGI &&
           FD_ISSET(conn->endpoint.cgi_sock, &read_set)) {
         read_from_cgi(conn);
       }
+#endif
       if (FD_ISSET(conn->client_sock, &write_set)) {
         conn->last_activity_time = current_time;
         write_to_client(conn);
-- 
GitLab