Add generic html-header reader to http server
authorHenning Rogge <hrogge@googlemail.com>
Sat, 21 Nov 2009 08:39:36 +0000 (09:39 +0100)
committerHenning Rogge <hrogge@googlemail.com>
Sat, 21 Nov 2009 08:39:36 +0000 (09:39 +0100)
refactoring of a few files to make the division between html and telnet server more clear

src/olsr_comport.c
src/olsr_comport_http.c
src/olsr_comport_http.h
src/olsr_comport_txt.c
src/olsr_comport_txt.h

index 23513aa..0be797f 100644 (file)
@@ -66,7 +66,6 @@
 #define HTTP_TIMEOUT  30000
 #define TXT_TIMEOUT 60000
 
-#define MAX_HTTP_PARA 10
 #define COMPORT_MAX_INPUTBUFFER 65536
 
 struct list_node olsr_comport_head;
@@ -87,10 +86,6 @@ static int olsr_com_openport(int port);
 static void olsr_com_parse_request(int fd, void *data, unsigned int flags);
 static void olsr_com_parse_connection(int fd, void *data, unsigned int flags);
 static void olsr_com_cleanup_session(struct comport_connection *con);
-static void olsr_com_parse_http(struct comport_connection *con,
-    unsigned int flags);
-static void olsr_com_parse_txt(struct comport_connection *con,
-    unsigned int flags);
 
 static void olsr_com_timeout_handler(void *);
 
@@ -393,266 +388,3 @@ static void olsr_com_parse_connection(int fd, void *data, unsigned int flags) {
   }
   return;
 }
-
-static void olsr_com_parse_http(struct comport_connection *con,
-    unsigned int flags  __attribute__ ((unused))) {
-  char *para_keyvalue[MAX_HTTP_PARA * 2] = { NULL }, *para = NULL, *str = NULL;
-  int para_count = 0;
-  char req_type[11] = { 0 };
-  char filename[252] = { 0 };
-  char filename_copy[252] = { 0 };
-  char http_version[11] = { 0 };
-
-  int idx = 0;
-  int i = 0;
-
-  /*
-   * find end of http header, might be useful for POST to keep the index !
-   * (implemented as a finite element automaton)
-   */
-
-  while (i < 5) {
-    switch (con->in.buf[idx++]) {
-      case '\0':
-        i = 6;
-        break;
-      case '\r':
-        i = (i == 3) ? 4 : 2;
-        break;
-      case '\n':
-        if (i == 1 || i == 4) {
-          i = 5;
-        } else if (i == 2) {
-          i = 3;
-        } else {
-          i = 1;
-        }
-        break;
-      default:
-        i = 0;
-        break;
-    }
-  }
-
-  if (i != 5) {
-    OLSR_DEBUG(LOG_COMPORT, "  need end of http header, still waiting...\n");
-    return;
-  }
-
-  /* got http header */
-  if (sscanf(con->in.buf, "%10s %250s %10s\n", req_type, filename, http_version)
-      != 3 || (strcmp(http_version, "HTTP/1.1") != 0 && strcmp(http_version,
-      "HTTP/1.0") != 0)) {
-    con->send_as = HTTP_400_BAD_REQ;
-    con->state = SEND_AND_QUIT;
-    return;
-  }
-
-  OLSR_DEBUG(LOG_COMPORT, "HTTP Request: %s %s %s\n", req_type, filename, http_version);
-
-  /* store a copy for the http_handlers */
-  strcpy(filename_copy, filename);
-  if (strcmp(req_type, "POST") == 0) {
-    /* load the rest of the header for POST commands */
-    char *lengthField = strstr(con->in.buf, "\nContent-Length:");
-    int clen = 0;
-
-    if (lengthField == NULL) {
-      con->send_as = HTTP_400_BAD_REQ;
-      con->state = SEND_AND_QUIT;
-      return;
-    }
-
-    sscanf(lengthField, "%*s %d\n", &clen);
-    if (con->in.len < idx + clen) {
-      /* we still need more data */
-      return;
-    }
-    para = &con->in.buf[idx];
-  }
-
-  /* strip the URL marker away */
-  str = strchr(filename, '#');
-  if (str) {
-    *str = 0;
-  }
-
-  /* we have everything to process the http request */
-  con->state = SEND_AND_QUIT;
-  olsr_com_decode_url(filename);
-
-  if (strcmp(req_type, "GET") == 0) {
-    /* HTTP-GET request */
-    para = strchr(filename, '?');
-    if (para != NULL) {
-      *para++ = 0;
-    }
-  } else if (strcmp(req_type, "POST") != 0) {
-    con->send_as = HTTP_501_NOT_IMPLEMENTED;
-    return;
-  }
-
-  /* handle HTTP GET & POST including parameters */
-  while (para && para_count < MAX_HTTP_PARA * 2) {
-    /* split the string at the next '=' (the key/value splitter) */
-    str = strchr(para, '=');
-    if (!str) {
-      break;
-    }
-    *str++ = 0;
-
-    /* we have null terminated key at *para. Now decode the key */
-    para_keyvalue[para_count++] = para;
-
-    /* split the string at the next '&' (the splitter of multiple key/value pairs */
-    para = strchr(str, '&');
-    if (para) {
-      *para++ = 0;
-    }
-
-    /* we have a null terminated value at *str, Now decode it */
-    para_keyvalue[para_count++] = str;
-  }
-
-  /* create body */
-  i = strlen(filename);
-
-  /*
-   * add a '/' at the end if it's not there to detect
-   *  paths without terminating '/' from the browser
-   */
-  if (filename[i - 1] != '/') {
-    strcat(filename, "/");
-  }
-
-  while (i > 0) {
-    if (olsr_com_handle_htmlsite(con, filename, filename_copy, para_count >> 1,
-        para_keyvalue)) {
-      return;
-    }
-
-    /* try to find a handler for a path prefix */
-    if (i > 0 && filename[i] == '/') {
-      filename[i--] = 0;
-    }
-    else {
-      do {
-        filename[i--] = 0;
-      } while (i > 0 && filename[i] != '/');
-    }
-  }
-  con->send_as = HTTP_404_NOT_FOUND;
-}
-
-static void olsr_com_parse_txt(struct comport_connection *con,
-    unsigned int flags  __attribute__ ((unused))) {
-  static char defaultCommand[] = "/link/neigh/topology/hna/mid/routes";
-  static char tmpbuf[128];
-
-  enum olsr_txtcommand_result res;
-  char *eol;
-  int len;
-  bool processedCommand = false, chainCommands = false;
-  uint32_t old_timeout;
-
-  old_timeout = con->timeout_value;
-
-  /* loop over input */
-  while (con->in.len > 0 && con->state == INTERACTIVE) {
-    char *para = NULL, *cmd = NULL, *next = NULL;
-
-    /* search for end of line */
-    eol = memchr(con->in.buf, '\n', con->in.len);
-
-    if (eol == NULL) {
-      break;
-    }
-
-    /* terminate line with a 0 */
-    if (eol != con->in.buf && eol[-1] == '\r') {
-      eol[-1] = 0;
-    }
-    *eol++ = 0;
-
-    /* handle line */
-    OLSR_DEBUG(LOG_COMPORT, "Interactive console: %s\n", con->in.buf);
-    cmd = &con->in.buf[0];
-    processedCommand = true;
-
-    /* apply default command */
-    if (strcmp(cmd, "/") == 0) {
-      strcpy(tmpbuf, defaultCommand);
-      cmd = tmpbuf;
-    }
-
-    if (cmd[0] == '/') {
-      cmd++;
-      chainCommands = true;
-    }
-    while (cmd) {
-      len = con->out.len;
-
-      /* handle difference between multicommand and singlecommand mode */
-      if (chainCommands) {
-        next = strchr(cmd, '/');
-        if (next) {
-          *next++ = 0;
-        }
-      }
-      para = strchr(cmd, ' ');
-      if (para != NULL) {
-        *para++ = 0;
-      }
-
-      /* if we are doing continous output, stop it ! */
-      if (con->stop_handler) {
-        con->stop_handler(con);
-        con->stop_handler = NULL;
-      }
-
-      if (strlen(cmd) != 0) {
-        res = olsr_com_handle_txtcommand(con, cmd, para);
-        switch (res) {
-          case CONTINUE:
-            break;
-          case CONTINOUS:
-            break;
-          case ABUF_ERROR:
-            con->out.len = len;
-            abuf_appendf(&con->out,
-                "Error in autobuffer during command '%s'.\n", cmd);
-            break;
-          case UNKNOWN:
-            con->out.len = len;
-            abuf_appendf(&con->out, "Error, unknown command '%s'\n", cmd);
-            break;
-          case QUIT:
-            con->state = SEND_AND_QUIT;
-            break;
-        }
-        /* put an empty line behind each command */
-        if (con->show_echo) {
-          abuf_puts(&con->out, "\n");
-        }
-      }
-      cmd = next;
-    }
-
-    /* remove line from input buffer */
-    abuf_pull(&con->in, eol - con->in.buf);
-
-    if (con->in.buf[0] == '/') {
-      /* end of multiple command line */
-      con->state = SEND_AND_QUIT;
-    }
-  }
-
-  /* reset timeout */
-  olsr_set_timer(&con->timeout, con->timeout_value, 0, false, &olsr_com_timeout_handler, con, connection_timeout);
-
-  /* print prompt */
-  if (processedCommand && con->state == INTERACTIVE && con->show_echo) {
-    abuf_puts(&con->out, "> ");
-  }
-}
-
index 3d1a793..788b5b4 100644 (file)
  * the copyright holders.
  *
  */
+
+#include <assert.h>
 #include <string.h>
 
 #include "common/autobuf.h"
 #include "common/avl.h"
+#include "common/string.h"
 #include "olsr_logging.h"
 #include "olsr_cookie.h"
 #include "olsr_comport.h"
@@ -50,6 +53,8 @@
 #include "olsr_cfg.h"
 #include "ipcalc.h"
 
+#define HTTP_TESTSITE
+
 static const char HTTP_VERSION[] = "HTTP/1.1";
 static const char TELNET_PATH[] = "/telnet/";
 
@@ -66,26 +71,48 @@ static char http_413_response[] = "Request Entity Too Large";
 static char http_501_response[] = "Not Implemented";
 static char http_503_response[] = "Service Unavailable";
 
+static bool parse_http_header(char *message, size_t message_len, struct http_header_data *data);
+
 /* sample for a static html page */
-#if 0
+#ifdef HTTP_TESTSITE
+
+static void
+test_handler(struct comport_connection *con, struct http_header_data *data) {
+  size_t i;
+
+  abuf_puts(&con->out, "<html><body>");
+  abuf_appendf(&con->out, "<br>Request: %s</br>\n", data->req_type);
+  abuf_appendf(&con->out, "<br>Filename: %s</br>\n", data->filename);
+  abuf_appendf(&con->out, "<br>Http-Version: %s</br>\n", data->http_version);
+
+  for (i=0; i<data->para_count; i++) {
+    abuf_appendf(&con->out, "<br>URL-Parameter: %s = %s</br>\n", data->para_key[i], data->para_value[i]);
+  }
+  for (i=0; i<data->header_count; i++) {
+    abuf_appendf(&con->out, "<br>Header: %s = %s</br>\n", data->header_key[i], data->header_value[i]);
+  }
+  abuf_puts(&con->out, "</body></html>");
+}
+
 static void init_test(void) {
   static char content[] = "<html><body>Yes, you got it !</body></html>";
-  static char path[] = "/";
   static char acl[] = "d2lraTpwZWRpYQ=="; /* base 64 .. this is "wikipedia" */
   static char *aclPtr[] = { acl };
   struct olsr_html_site *site;
 
-  site = olsr_com_add_htmlsite(path, content, strlen(content));
+  site = olsr_com_add_htmlsite("/", content, strlen(content));
   olsr_com_set_htmlsite_acl_auth(site, NULL, 1, aclPtr);
+
+  olsr_com_add_htmlhandler(test_handler, "/print/");
 }
 #endif
 
 static void
-olsr_com_html2telnet_gate(struct comport_connection *con, char *path, int pCount, char *p[]) {
-  if (strlen(path) > strlen(TELNET_PATH)) {
-    char *cmd = &path[strlen(TELNET_PATH)];
+olsr_com_html2telnet_gate(struct comport_connection *con, struct http_header_data *data) {
+  if (strlen(data->filename) > strlen(TELNET_PATH)) {
+    char *cmd = &data->filename[strlen(TELNET_PATH)];
     char *next;
-    int count = 1;
+    size_t count = 1;
     enum olsr_txtcommand_result result;
 
     while (cmd) {
@@ -94,7 +121,7 @@ olsr_com_html2telnet_gate(struct comport_connection *con, char *path, int pCount
         *next++ = 0;
       }
 
-      result = olsr_com_handle_txtcommand(con, cmd, pCount > count ? p[count] : NULL);
+      result = olsr_com_handle_txtcommand(con, cmd, data->para_count > count ? data->para_value[count] : NULL);
 
       /* sorry, no continous output */
       if (result == CONTINOUS) {
@@ -109,7 +136,7 @@ olsr_com_html2telnet_gate(struct comport_connection *con, char *path, int pCount
         con->send_as = HTTP_400_BAD_REQ;
       }
       cmd = next;
-      count += 2;
+      count ++;
     }
   }
 }
@@ -123,7 +150,9 @@ olsr_com_init_http(void) {
 
   /* activate telnet gateway */
   olsr_com_add_htmlhandler(olsr_com_html2telnet_gate, TELNET_PATH);
-  //init_test();
+#ifdef HTTP_TESTSITE
+  init_test();
+#endif
 }
 
 void olsr_com_destroy_http(void) {
@@ -134,7 +163,7 @@ void olsr_com_destroy_http(void) {
 }
 
 struct olsr_html_site *
-olsr_com_add_htmlsite(char *path, char *content, size_t length) {
+olsr_com_add_htmlsite(const char *path, const char *content, size_t length) {
   struct olsr_html_site *site;
 
   site = olsr_cookie_malloc(htmlsite_cookie);
@@ -149,7 +178,7 @@ olsr_com_add_htmlsite(char *path, char *content, size_t length) {
 }
 
 struct olsr_html_site *
-olsr_com_add_htmlhandler(void(*sitehandler)(struct comport_connection *con, char *path, int parameter_count, char *parameters[]),
+olsr_com_add_htmlhandler(void(*sitehandler)(struct comport_connection *con, struct http_header_data *data),
     const char *path) {
   struct olsr_html_site *site;
 
@@ -180,9 +209,9 @@ olsr_com_set_htmlsite_acl_auth(struct olsr_html_site *site, struct ip_acl *ipacl
 /* handle the html site. returns true on successful handling (even if it was unauthorized)
  * false if we did not find a site
 */
-bool
+static bool
 olsr_com_handle_htmlsite(struct comport_connection *con, char *path,
-    char *fullpath, int para_count, char **para) {
+    struct http_header_data *data) {
   char *str;
   int i;
   struct olsr_html_site *site;
@@ -230,12 +259,358 @@ olsr_com_handle_htmlsite(struct comport_connection *con, char *path,
   if (site->static_site) {
     abuf_memcpy(&con->out, site->site_data, site->site_length);
   } else {
-    site->sitehandler(con, fullpath, para_count, para);
+    site->sitehandler(con, data);
   }
   con->send_as = HTTP_200_OK;
   return true;
 }
 
+static bool parse_http_header(char *message, size_t message_len, struct http_header_data *data)
+{
+  size_t header_index;
+  char *start;
+  bool was_space = false;
+
+  assert(message);
+  assert(data);
+
+  memset(data, 0, sizeof(struct http_header_data));
+  data->req_type = message;
+
+  start = message;
+  while(true)
+  {
+    if(message_len < 1) {
+      OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+      return true;
+    }
+
+    if (was_space) {
+      if (data->filename == NULL) {
+        data->filename = message;
+      }
+      else if (data->http_version == NULL) {
+        data->http_version = message;
+      }
+      was_space = false;
+    }
+    if(*message == ' ' && data->http_version == NULL) {
+      *message = '\0';
+      was_space = true;
+    }
+    else if(*message == '\r') {
+      *message = '\0';
+    }
+    else if(*message == '\n')
+    {
+      *message = '\0';
+      message++; message_len--;
+      break;
+    }
+
+    message++; message_len--;
+  }
+
+  for(header_index = 0; true; header_index++)
+  {
+    if(message_len < 1) {
+      OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+      return true;
+    }
+
+    if(*message == '\n')
+    {
+      break;
+    }
+    else if(*message == '\r')
+    {
+      if(message_len < 2) return true;
+
+      if(message[1] == '\n')
+      {
+        break;
+      }
+    }
+
+    if(header_index >= MAX_HTTP_HEADERS) {
+      OLSR_DEBUG(LOG_COMPORT, "Error, too many http header entries (%zu)\n", message - start);
+      return true;
+    }
+
+    data->header_key[header_index] = message;
+
+    while(true)
+    {
+      if(message_len < 1) {
+        OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+        return true;
+      }
+
+      if(*message == ':')
+      {
+        *message = '\0';
+
+        message++; message_len--;
+        break;
+      }
+      else if(*message == ' ' || *message == '\t')
+      {
+        *message = '\0';
+      }
+      else if(*message == '\n' || *message == '\r')
+      {
+        OLSR_DEBUG(LOG_COMPORT, "Error, http-header has wrong ending (%zu)\n", message - start);
+        return true;
+      }
+
+      message++; message_len--;
+    }
+
+    data->header_value[header_index] = NULL;
+
+    while(true)
+    {
+      if(message_len < 1) {
+        OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+        return true;
+      }
+
+      if(data->header_value[header_index] == NULL)
+      {
+        if(*message != ' ' && *message != '\t')
+        {
+          data->header_value[header_index] = message;
+        }
+      }
+
+      if(*message == '\n')
+      {
+        if(message_len < 2) {
+          OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+          return true;
+        }
+
+        if(message[1] == ' ' || message[1] == '\t')
+        {
+          *message = ' ';
+          message[1] = ' ';
+
+          message += 2; message_len -= 2;
+          continue;
+        }
+
+        *message = '\0';
+
+        if(data->header_value[header_index] == NULL)
+        {
+          data->header_value[header_index] = message;
+        }
+
+        message++; message_len--;
+        break;
+      }
+      else if(*message == '\r')
+      {
+        if(message_len < 2) {
+          OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+          return true;
+        }
+
+        if(message[1] == '\n')
+        {
+          if(message_len < 3) {
+            OLSR_DEBUG(LOG_COMPORT, "Error, http-header too small (%zu)\n", message - start);
+            return true;
+          }
+
+          if(message[2] == ' ' || message[2] == '\t')
+          {
+            *message = ' ';
+            message[1] = ' ';
+            message[2] = ' ';
+
+            message += 3; message_len -= 3;
+            continue;
+          }
+
+          *message = '\0';
+
+          if(data->header_value[header_index] == NULL)
+          {
+            data->header_value[header_index] = message;
+          }
+
+          message += 2; message_len -= 2;
+          break;
+        }
+      }
+
+      message++; message_len--;
+    }
+  }
+
+  data->header_count = header_index;
+  return false;
+}
+
+void olsr_com_parse_http(struct comport_connection *con,
+    unsigned int flags  __attribute__ ((unused))) {
+  struct http_header_data data;
+  char *para = NULL, *str = NULL;
+  char processed_filename[256];
+  int idx = 0;
+  size_t i = 0;
+
+  /*
+   * find end of http header, might be useful for POST to keep the index !
+   * (implemented as a finite element automaton)
+   */
+
+  while (i < 5) {
+    switch (con->in.buf[idx++]) {
+      case '\0':
+        i = 6;
+        break;
+      case '\r':
+        i = (i == 3) ? 4 : 2;
+        break;
+      case '\n':
+        if (i == 1 || i == 4) {
+          i = 5;
+        } else if (i == 2) {
+          i = 3;
+        } else {
+          i = 1;
+        }
+        break;
+      default:
+        i = 0;
+        break;
+    }
+  }
+
+  if (i != 5) {
+    OLSR_DEBUG(LOG_COMPORT, "  need end of http header, still waiting...\n");
+    return;
+  }
+
+  /* got http header */
+
+  if (parse_http_header(con->in.buf, con->in.len, &data)) {
+    OLSR_DEBUG(LOG_COMPORT, "Error, illegal http header.\n");
+    con->send_as = HTTP_400_BAD_REQ;
+    con->state = SEND_AND_QUIT;
+    return;
+  }
+
+  if (strcmp(data.http_version, "HTTP/1.1") != 0 && strcmp(data.http_version, "HTTP/1.0") != 0) {
+    OLSR_DEBUG(LOG_COMPORT, "Unknown Http-Version: '%s'\n", data.http_version);
+    con->send_as = HTTP_400_BAD_REQ;
+    con->state = SEND_AND_QUIT;
+    return;
+  }
+
+  OLSR_DEBUG(LOG_COMPORT, "HTTP Request: %s %s %s\n", data.req_type, data.filename, data.http_version);
+
+  /* store a copy for the http_handlers */
+  strscpy(processed_filename, data.filename, sizeof(processed_filename));
+  if (strcmp(data.req_type, "POST") == 0) {
+    /* load the rest of the header for POST commands */
+    int clen;
+
+    for (i=0, clen=-1; i<data.header_count; i++) {
+      if (strcasecmp(data.header_key[i], "Content-Length") == 0) {
+        clen = atoi(data.header_value[i]);
+        break;
+      }
+    }
+
+    if (clen == -1) {
+      con->send_as = HTTP_400_BAD_REQ;
+      con->state = SEND_AND_QUIT;
+      return;
+    }
+
+    if (con->in.len < idx + clen) {
+      /* we still need more data */
+      return;
+    }
+    para = &con->in.buf[idx];
+  }
+
+  /* strip the URL marker away */
+  str = strchr(processed_filename, '#');
+  if (str) {
+    *str = 0;
+  }
+
+  /* we have everything to process the http request */
+  con->state = SEND_AND_QUIT;
+  olsr_com_decode_url(processed_filename);
+
+  if (strcmp(data.req_type, "GET") == 0) {
+    /* HTTP-GET request */
+    para = strchr(processed_filename, '?');
+    if (para != NULL) {
+      *para++ = 0;
+    }
+  } else if (strcmp(data.req_type, "POST") != 0) {
+    con->send_as = HTTP_501_NOT_IMPLEMENTED;
+    return;
+  }
+
+  /* handle HTTP GET & POST including parameters */
+  while (para && data.para_count < MAX_HTTP_PARA) {
+    /* split the string at the next '=' (the key/value splitter) */
+    str = strchr(para, '=');
+    if (!str) {
+      break;
+    }
+    *str++ = 0;
+
+    /* we have null terminated key at *para. Now decode the key */
+    data.para_key[data.para_count] = para;
+
+    /* split the string at the next '&' (the splitter of multiple key/value pairs */
+    para = strchr(str, '&');
+    if (para) {
+      *para++ = 0;
+    }
+
+    /* we have a null terminated value at *str, Now decode it */
+    data.para_value[data.para_count] = str;
+    data.para_count++;
+  }
+
+  /* create body */
+  i = strlen(processed_filename);
+
+  /*
+   * add a '/' at the end if it's not there to detect
+   *  paths without terminating '/' from the browser
+   */
+  if (processed_filename[i - 1] != '/' && data.para_count == 0) {
+    strcat(processed_filename, "/");
+  }
+
+  while (i > 0) {
+    if (olsr_com_handle_htmlsite(con, processed_filename, &data)) {
+      return;
+    }
+
+    /* try to find a handler for a path prefix */
+    if (i > 0 && processed_filename[i] == '/') {
+      processed_filename[i--] = 0;
+    }
+    else {
+      do {
+        processed_filename[i--] = 0;
+      } while (i > 0 && processed_filename[i] != '/');
+    }
+  }
+  con->send_as = HTTP_404_NOT_FOUND;
+}
+
 void
 olsr_com_build_httpheader(struct comport_connection *con) {
   struct autobuf buf;
index 8b4e4a2..0fb6d64 100644 (file)
 #include "olsr_ip_acl.h"
 #include "olsr_comport.h"
 
+#define MAX_HTTP_PARA 10
+#define MAX_HTTP_HEADERS 32
+
+/* this is the data about the http header delivered to the html site handler */
+struct http_header_data {
+  char *para_key[MAX_HTTP_PARA];
+  char *para_value[MAX_HTTP_PARA];
+  char *header_key[MAX_HTTP_HEADERS];
+  char *header_value[MAX_HTTP_HEADERS];
+  char *req_type;
+  char *filename;
+  char *http_version;
+  size_t para_count;
+  size_t header_count;
+};
+
 /* this is a html site datastructure for each site */
 /* it is stored in an AVL tree */
 struct olsr_html_site {
@@ -59,11 +75,11 @@ struct olsr_html_site {
   struct ip_acl *acl; /* allow only certain IPs ? */
 
        /* for static sites... */
-  char *site_data;
+  const char *site_data;
   size_t site_length;
 
        /* for non static, this is the handler */
-  void (*sitehandler)(struct comport_connection *con, char *path, int parameter_count, char *parameters[]);
+  void (*sitehandler)(struct comport_connection *con, struct http_header_data *data);
 };
 
 AVLNODE2STRUCT(html_tree2site, olsr_html_site, node);
@@ -74,17 +90,16 @@ void olsr_com_init_http(void);
 void olsr_com_destroy_http(void);
 
 struct olsr_html_site *EXPORT(olsr_com_add_htmlsite) (
-    char *path, char *content, size_t length);
+    const char *path, const char *content, size_t length);
 struct olsr_html_site *EXPORT(olsr_com_add_htmlhandler) (
-    void (*sitehandler)(struct comport_connection *con, char *path, int parameter_count, char *parameters[]),
+    void (*sitehandler)(struct comport_connection *con, struct http_header_data *data),
     const char *path);
 void EXPORT(olsr_com_remove_htmlsite) (struct olsr_html_site *site);
 void EXPORT(olsr_com_set_htmlsite_acl_auth) (struct olsr_html_site *site,
     struct ip_acl *acl, int auth_count, char **auth_entries);
 
-bool olsr_com_handle_htmlsite(struct comport_connection *con, char *path,
-    char *filename, int para_count, char **para);
-
+void olsr_com_parse_http(struct comport_connection *con,
+    unsigned int flags  __attribute__ ((unused)));
 void EXPORT(olsr_com_build_httpheader) (struct comport_connection *con);
 void EXPORT(olsr_com_create_httperror) (struct comport_connection *con);
 char *EXPORT(olsr_com_get_http_message) (enum http_header_type type);
index 5370ce6..ac98d30 100644 (file)
@@ -199,6 +199,118 @@ olsr_com_handle_txtcommand(struct comport_connection *con, char *cmd, char *para
   return ptr->handler(con, cmd, param);
 }
 
+void olsr_com_parse_txt(struct comport_connection *con,
+    unsigned int flags  __attribute__ ((unused))) {
+  static char defaultCommand[] = "/link/neigh/topology/hna/mid/routes";
+  static char tmpbuf[128];
+
+  enum olsr_txtcommand_result res;
+  char *eol;
+  int len;
+  bool processedCommand = false, chainCommands = false;
+  uint32_t old_timeout;
+
+  old_timeout = con->timeout_value;
+
+  /* loop over input */
+  while (con->in.len > 0 && con->state == INTERACTIVE) {
+    char *para = NULL, *cmd = NULL, *next = NULL;
+
+    /* search for end of line */
+    eol = memchr(con->in.buf, '\n', con->in.len);
+
+    if (eol == NULL) {
+      break;
+    }
+
+    /* terminate line with a 0 */
+    if (eol != con->in.buf && eol[-1] == '\r') {
+      eol[-1] = 0;
+    }
+    *eol++ = 0;
+
+    /* handle line */
+    OLSR_DEBUG(LOG_COMPORT, "Interactive console: %s\n", con->in.buf);
+    cmd = &con->in.buf[0];
+    processedCommand = true;
+
+    /* apply default command */
+    if (strcmp(cmd, "/") == 0) {
+      strcpy(tmpbuf, defaultCommand);
+      cmd = tmpbuf;
+    }
+
+    if (cmd[0] == '/') {
+      cmd++;
+      chainCommands = true;
+    }
+    while (cmd) {
+      len = con->out.len;
+
+      /* handle difference between multicommand and singlecommand mode */
+      if (chainCommands) {
+        next = strchr(cmd, '/');
+        if (next) {
+          *next++ = 0;
+        }
+      }
+      para = strchr(cmd, ' ');
+      if (para != NULL) {
+        *para++ = 0;
+      }
+
+      /* if we are doing continous output, stop it ! */
+      if (con->stop_handler) {
+        con->stop_handler(con);
+        con->stop_handler = NULL;
+      }
+
+      if (strlen(cmd) != 0) {
+        res = olsr_com_handle_txtcommand(con, cmd, para);
+        switch (res) {
+          case CONTINUE:
+            break;
+          case CONTINOUS:
+            break;
+          case ABUF_ERROR:
+            con->out.len = len;
+            abuf_appendf(&con->out,
+                "Error in autobuffer during command '%s'.\n", cmd);
+            break;
+          case UNKNOWN:
+            con->out.len = len;
+            abuf_appendf(&con->out, "Error, unknown command '%s'\n", cmd);
+            break;
+          case QUIT:
+            con->state = SEND_AND_QUIT;
+            break;
+        }
+        /* put an empty line behind each command */
+        if (con->show_echo) {
+          abuf_puts(&con->out, "\n");
+        }
+      }
+      cmd = next;
+    }
+
+    /* remove line from input buffer */
+    abuf_pull(&con->in, eol - con->in.buf);
+
+    if (con->in.buf[0] == '/') {
+      /* end of multiple command line */
+      con->state = SEND_AND_QUIT;
+    }
+  }
+
+  /* reset timeout */
+  olsr_change_timer(con->timeout, con->timeout_value, 0, false);
+
+  /* print prompt */
+  if (processedCommand && con->state == INTERACTIVE && con->show_echo) {
+    abuf_puts(&con->out, "> ");
+  }
+}
+
 static enum olsr_txtcommand_result
 olsr_txtcmd_quit(struct comport_connection *con __attribute__ ((unused)),
     const char *cmd __attribute__ ((unused)), const char *param __attribute__ ((unused))) {
index 116945c..59886aa 100644 (file)
@@ -76,7 +76,7 @@ struct olsr_txtcommand *EXPORT(olsr_com_add_help_txtcommand) (
     const char *command, olsr_txthandler handler);
 void EXPORT(olsr_com_remove_normal_txtcommand) (struct olsr_txtcommand *cmd);
 void EXPORT(olsr_com_remove_help_txtcommand) (struct olsr_txtcommand *cmd);
-
+void olsr_com_parse_txt(struct comport_connection *con, unsigned int flags);
 enum olsr_txtcommand_result olsr_com_handle_txtcommand(struct comport_connection *con,
     char *command, char *parameter);