[nagiosplug] Generic HTTP header parser

Thomas Guyot-Sionnest dermoth at users.sourceforge.net
Fri Sep 9 07:34:44 CEST 2011


 Module: nagiosplug
 Branch: pu_dermoth_http
 Commit: 51f4ed226eb6a889627b612e8ce7e40ec6f939fd
 Author: Thomas Guyot-Sionnest <dermoth at aei.ca>
   Date: Fri Sep  9 01:30:58 2011 -0400
    URL: http://nagiosplug.git.sf.net/git/gitweb.cgi?p=nagiosplug/nagiosplug;a=commit;h=51f4ed2

Generic HTTP header parser

---

 plugins/check_http.c |  197 +++++++++++++++++++++++++++++++-------------------
 1 files changed, 122 insertions(+), 75 deletions(-)

diff --git a/plugins/check_http.c b/plugins/check_http.c
index 433c28e..eb9cd2c 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -951,6 +951,10 @@ check_http (void)
   }
   page += (size_t) strspn (page, "\r\n");
   header[pos - header] = 0;
+
+  /* Decode chunked encoding if needed */
+  /* TODO: write chunked_decode() */
+
   if (verbose)
     printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header,
                 (no_body ? "  [[ skipped ]]" : page));
@@ -1110,8 +1114,82 @@ check_http (void)
 #define HD4 URI_HTTP "://" URI_HOST
 #define HD5 URI_PATH
 
+#define GOBBLE_HEADER(x) while (strlen(x) >= 1 && x[0] != '\r' && x[1] != '\n') { x++; } x+=2;
+#define LENGTH_EOL(x, i) i=0; while (strlen(x+i) >= 1 && x[i] != '\r' && x[i+1] != '\n') { i++; }
+#define CHECK_LWS(x) x[0] == ' ' || x[0] == '\t'
+
+/* Get named header (won't merge repeatable headers) */
+char *
+header_get_single(const char *header, const char *key)
+{
+  char *c, *tmp, *value;
+  char *x=(char *)header;
+  int i;
+
+  while (x) {
+    /* compare line with key */
+    for (c=(char *)key; strlen(c); c++, x++) {
+      if (tolower(c[0]) == tolower(c[0])) continue;
+      break;
+    }
+    if (c[0] == '\0' && x[0] == ':') {
+      x++;
+      /* Match, strip heading spaces */
+      while (CHECK_LWS(x)) x++;
+      /* Get the rest... */
+      LENGTH_EOL(x, i)
+      /* strip trailing spaces */
+      while (CHECK_LWS((x+i-1))) i--;
+      value = strndup(x, i);
+      /* Get to next line */
+      x += i+2;
+      /* RFC 2616 (4.2):  ``Header fields can be extended over multiple lines by
+       * preceding each extra line with at least one SP or HT.'' */
+      while (x && CHECK_LWS(x)) {
+        /* again: strip, copy, strip */
+        while (CHECK_LWS(x)) x++;
+        tmp = value;
+        LENGTH_EOL(x, i)
+        while (CHECK_LWS((x+i-1))) i--;
+        c = strndup(x, i);
+        asprintf(&value, "%s %s", value, c); //FIXME: check ret
+        free(tmp);
+        free(c);
+        /* Get to next line; lather, rinse, repeat */
+        x += i+2;
+      }
+      return value;
+    } else {
+      /* No match, walk to next header */
+      GOBBLE_HEADER(x)
+      while (x && CHECK_LWS(x)) {
+        /* extended headers... */
+        GOBBLE_HEADER(x)
+      }
+    }
+
+
+  //int len=strlen(key);
+    //if (strncasecmp(x, key, len) == 0 && x[len] == ':') {
+    //  /* We've got a winner */
+    //  x += len+1;
+    //  /* strip heading */
+    //  x += strspn(x, "\t ");
+    //  value = strndup(x, strcspn(x, "\r\n"));
+    //  /* Strip end */
+    //  for (c=value[strlen(x)]);
+    //}
+    /* FIXME, multiple headers? */
+    //GOBBLE_HEADER(x);
+  }
+
+  return NULL;
+
+}
+
+/* FIXME: Make a function to check for Content-encoding */
 void
-redir (char *pos, char *status_line)
+redir (char *p, char *status_line)
 {
   int i = 0;
   char *x;
@@ -1119,94 +1197,63 @@ redir (char *pos, char *status_line)
   char type[6];
   char *addr;
   char *url;
+  char *pos;
 
   addr = malloc (MAX_IPV4_HOSTLENGTH + 1);
   if (addr == NULL)
     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate addr\n"));
 
-  url = malloc (strcspn (pos, "\r\n"));
+  url = header_get_single(p, "Location");
+  /* hack... a very ugly one */
+  asprintf(&pos, "%s\r\n", url);
+
   if (url == NULL)
     die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
 
-  while (pos) {
-    sscanf (pos, "%1[Ll]%*1[Oo]%*1[Cc]%*1[Aa]%*1[Tt]%*1[Ii]%*1[Oo]%*1[Nn]:%n", xx, &i);
-    if (i == 0) {
-      pos += (size_t) strcspn (pos, "\r\n");
-      pos += (size_t) strspn (pos, "\r\n");
-      if (strlen(pos) == 0)
-        die (STATE_UNKNOWN,
-             _("HTTP UNKNOWN - Could not find redirect location - %s%s\n"),
-             status_line, (display_html ? "</A>" : ""));
-      continue;
-    }
-
-    pos += i;
-    pos += strspn (pos, " \t");
-
-    /*
-     * RFC 2616 (4.2):  ``Header fields can be extended over multiple lines by
-     * preceding each extra line with at least one SP or HT.''
-     */
-    for (; (i = strspn (pos, "\r\n")); pos += i) {
-      pos += i;
-      if (!(i = strspn (pos, " \t"))) {
-        die (STATE_UNKNOWN, _("HTTP UNKNOWN - Empty redirect location%s\n"),
-             display_html ? "</A>" : "");
-      }
-    }
-
-    url = realloc (url, strcspn (pos, "\r\n") + 1);
-    if (url == NULL)
-      die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
-
-    /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
-    if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
-      url = prepend_slash (url);
-      use_ssl = server_type_check (type);
-    }
-
-    /* URI_HTTP URI_HOST URI_PATH */
-    else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
-      url = prepend_slash (url);
-      use_ssl = server_type_check (type);
-      i = server_port_check (use_ssl);
-    }
+  /* URI_HTTP, URI_HOST, URI_PORT, URI_PATH */
+  if (sscanf (pos, HD1, type, addr, &i, url) == 4) {
+    url = prepend_slash (url);
+    use_ssl = server_type_check (type);
+  }
 
-    /* URI_HTTP URI_HOST URI_PORT */
-    else if (sscanf (pos, HD3, type, addr, &i) == 3) {
-      strcpy (url, HTTP_URL);
-      use_ssl = server_type_check (type);
-    }
+  /* URI_HTTP URI_HOST URI_PATH */
+  else if (sscanf (pos, HD2, type, addr, url) == 3 ) {
+    url = prepend_slash (url);
+    use_ssl = server_type_check (type);
+    i = server_port_check (use_ssl);
+  }
 
-    /* URI_HTTP URI_HOST */
-    else if (sscanf (pos, HD4, type, addr) == 2) {
-      strcpy (url, HTTP_URL);
-      use_ssl = server_type_check (type);
-      i = server_port_check (use_ssl);
-    }
+  /* URI_HTTP URI_HOST URI_PORT */
+  else if (sscanf (pos, HD3, type, addr, &i) == 3) {
+    strcpy (url, HTTP_URL);
+    use_ssl = server_type_check (type);
+  }
 
-    /* URI_PATH */
-    else if (sscanf (pos, HD5, url) == 1) {
-      /* relative url */
-      if ((url[0] != '/')) {
-        if ((x = strrchr(server_url, '/')))
-          *x = '\0';
-        asprintf (&url, "%s/%s", server_url, url);
-      }
-      i = server_port;
-      strcpy (type, server_type);
-      strcpy (addr, host_name ? host_name : server_address);
-    }
+  /* URI_HTTP URI_HOST */
+  else if (sscanf (pos, HD4, type, addr) == 2) {
+    strcpy (url, HTTP_URL);
+    use_ssl = server_type_check (type);
+    i = server_port_check (use_ssl);
+  }
 
-    else {
-      die (STATE_UNKNOWN,
-           _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
-           pos, (display_html ? "</A>" : ""));
+  /* URI_PATH */
+  else if (sscanf (pos, HD5, url) == 1) {
+    /* relative url */
+    if ((url[0] != '/')) {
+      if ((x = strrchr(server_url, '/')))
+        *x = '\0';
+      asprintf (&url, "%s/%s", server_url, url);
     }
+    i = server_port;
+    strcpy (type, server_type);
+    strcpy (addr, host_name ? host_name : server_address);
+  }
 
-    break;
-
-  } /* end while (pos) */
+  else {
+    die (STATE_UNKNOWN,
+         _("HTTP UNKNOWN - Could not parse redirect location - %s%s\n"),
+         pos, (display_html ? "</A>" : ""));
+  }
 
   if (++redir_depth > max_depth)
     die (STATE_WARNING,





More information about the Commits mailing list