Code

* integrate necessary cgi functionality into rrd_cgi.c so that libcgi is not
authoroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Sat, 12 Nov 2005 23:10:48 +0000 (23:10 +0000)
committeroetiker <oetiker@a5681a0c-68f1-0310-ab6d-d61299d08faa>
Sat, 12 Nov 2005 23:10:48 +0000 (23:10 +0000)
  required anymore ...  -- D. Walsh <buildsmart at daleenterprise.com>

* check if we have to include malloc/malloc.h to make malloc work ... -- tobi

git-svn-id: svn://svn.oetiker.ch/rrdtool/branches/1.2/program@708 a5681a0c-68f1-0310-ab6d-d61299d08faa

configure.ac
doc/rrdbuild.pod
src/Makefile.am
src/rrd_cgi.c

index e2d5c6af5f646870fd4263678095093dfab85d88..9f59bb70de160544e9c0d3a8a54b92abe53663c0 100644 (file)
@@ -78,6 +78,10 @@ char *strchr (), *strrchr ();
 # define rrd_realloc(a,b) realloc((a), (b))
 #endif      
 
+#if NEED_MALLOC_MALLOC_H
+#  include <malloc/malloc.h>
+#endif
+
 #if HAVE_MATH_H
 #  include <math.h>
 #endif
@@ -222,6 +226,29 @@ volatile int x;volatile float f;  ]], [[x = isinf(f)]])],[AC_MSG_RESULT(yes)
 
 AC_FULL_IEEE
 
+AC_LANG_PUSH(C)
+dnl see if we have to include malloc/malloc.h
+AC_MSG_CHECKING([do we need malloc/malloc.h])
+AC_LINK_IFELSE(
+    AC_LANG_PROGRAM(
+           [[#include <stdlib.h>]],
+           [[malloc(1)]]
+                   ),
+    [ AC_MSG_RESULT([nope, works out of the box]) ],
+    [ AC_LINK_IFELSE(
+          AC_LANG_PROGRAM(
+                [[#include <stdlib.h>
+                  #include <malloc/malloc.h>]],
+                [[malloc(1)]]
+                        ),
+          [AC_DEFINE(NEED_MALLOC_MALLOC_H)
+           AC_MSG_RESULT([yes we do])],
+          [AC_MSG_ERROR([Can't figure how to compile malloc])]
+      )
+    ]  
+)
+AC_LANG_POP(C)
+
 dnl How the vertical axis label is printed
 AC_ARG_VAR(RRDGRAPH_YLEGEND_ANGLE, 
  [Vertical label angle: 90.0 (default) or 270.0])
@@ -238,26 +265,6 @@ EX_CHECK_ALL(z,          zlibVersion,               zlib.h,                 zlib
 EX_CHECK_ALL(png,        png_access_version_number, png.h,                  libpng,      1.2.8,  http://prdownloads.sourceforge.net/libpng/, "")
 EX_CHECK_ALL(freetype,   FT_Init_FreeType,          ft2build.h,                    freetype2,   2.1.9,  http://prdownloads.sourceforge.net/freetype/, /usr/include/freetype2)
 
-save_LIBS=${LIBS}
-save_CPPFLAGS=${CPPFLAGS}
-save_LDFLAGS=${LDFLAGS}
-
-if test $enable_rrdcgi != no; then
-EX_CHECK_ALL(cgi,        cgiInit,                   cgi.h,                  cgilib,      0.5,    http://www.infodrom.org/projects/cgilib, "")
-fi
-
-CGI_LIBS=${LIBS}
-CGI_CPPFLAGS=${CPPFLAGS}
-CGI_LDFLAGS=${LDFLAGS}
-
-AC_SUBST(CGI_LIBS)
-AC_SUBST(CGI_CPPFLAGS)
-AC_SUBST(CGI_LDFLAGS)
-
-LIBS=${save_LIBS}
-CPPFLAGS=${save_CPPFLAGS}
-LDFLAGS=${save_LDFLAGS}
-
 if test "$EX_CHECK_ALL_ERR" = "YES"; then
   AC_MSG_ERROR([Please fix the library issues listed above and try again.])
 fi
index 0c872beabf2bbd3c74ae246e96f258ad1878aeb6..b2dfba2e60f2d3929d0a28899526910298c06b27 100644 (file)
@@ -69,25 +69,6 @@ compile your own copies of the required libraries. Here is how:
 
 =over
 
-=item Building cgilib
-
- cd $BUILD_DIR
- wget http://people.ee.ethz.ch/oetiker/webtools/rrdtool/pub/libs/cgilib-0.5.tar.gz
- tar zxf cgilib-0.5.tar.gz
- cd cgilib-0.5
-
-If you are on Mac OSX you want to fix a little header problem here by doing
-
- touch malloc.h
-
-and now you are ready to build
-
- make CC=gcc CFLAGS="-O3 -fPIC -I."
- mkdir -p $BUILD_DIR/lb/include
- cp *.h $BUILD_DIR/lb/include
- mkdir -p $BUILD_DIR/lb/lib
- cp libcgi* $BUILD_DIR/lb/lib
-
 =item Building zlib
 
  cd $BUILD_DIR
@@ -149,10 +130,6 @@ will do just fine without since their F<ar> command does ranlibs job as well.
 
  ranlib $BUILD_DIR/lb/lib/*.a
 
-Note for OpenBSD users: It seems that libcgi fails to build properly on some
-of these systems. Run F<ar rc libcgi.a cgi.o cookies.o> to get a propper
-library if you find that libcgi.a is only a few bytes in size.
-
 This time you tell configure where it should be looking for libraries and
 include files. This is done via environment variables. Depending on the
 shell you are running, the syntax for setting environment variables is
index 6bee6b71b0109a24128c4e1a60e83a814d6ac075..d029600014807b035b51263a100efc4498b0170d 100644 (file)
@@ -7,7 +7,7 @@
 fontsdir =  $(datadir)/rrdtool/fonts
 fonts_DATA = DejaVuSansMono-Roman.ttf
 
-#INCLUDES = $(CGI_INCLUDES) $(FREETYPE_INCLUDES) $(ART_INCLUDES) \
+#INCLUDES = $(FREETYPE_INCLUDES) $(ART_INCLUDES) \
 #           $(PNG_INCLUDES) $(ZLIB_INCLUDES)
 RRD_DEFAULT_FONT=@RRD_DEFAULT_FONT@
 AM_CPPFLAGS = -DRRD_DEFAULT_FONT=\"$(RRD_DEFAULT_FONT)\" -DNUMVERS=@NUMVERS@
@@ -108,14 +108,13 @@ include_HEADERS   = rrd.h
 #librrd_private_la_LDFLAGS = -static
 
 bin_PROGRAMS   = rrdtool rrdupdate
+
 if BUILD_RRDCGI
 bin_PROGRAMS += rrdcgi
 endif
 
 rrdcgi_SOURCES = rrd_cgi.c
 rrdcgi_LDADD   = librrd.la
-rrdcgi_CPPFLAGS = $(AM_CPPFLAGS) @CGI_CPPFLAGS@
-rrdcgi_LDFLAGS = @CGI_LDFLAGS@ @CGI_LIBS@
 
 rrdupdate_SOURCES = 
 rrdupdate_LDADD        = rrdupdate.o librrd.la
index 2daa5a5f13ad1f9b3ecd39b393001d6c3a5eeb42..17a6b16b97f64919957f0221cbcc6ce9b3fee094 100644 (file)
@@ -5,16 +5,19 @@
  *****************************************************************************/
 
 #include "rrd_tool.h"
-#include <cgi.h>
-#include <time.h>
 
 
 #define MEMBLK 1024
 /*#define DEBUG_PARSER
 #define DEBUG_VARS*/
 
-/* global variable for libcgi */
-s_cgi *cgiArg;
+typedef struct var_s {
+       char    *name, *value;
+} s_var;
+
+typedef struct cgi_s {
+       s_var **vars;
+} s_cgi;
 
 /* in arg[0] find tags beginning with arg[1] call arg[2] on them
    and replace by result of arg[2] call */
@@ -70,6 +73,64 @@ char *http_time(time_t *);
 /* return a pointer to newly allocated copy of this string */
 char *stralloc(const char *);
 
+/* global variable for rrdcgi */
+s_cgi *rrdcgiArg;
+
+/* rrdcgiHeader
+ * 
+ *  Prints a valid CGI Header (Content-type...) etc.
+ */
+void rrdcgiHeader(void);
+
+/* rrdcgiDecodeString
+ * decode html escapes
+ */
+char *rrdcgiDecodeString(char *text);
+
+/* rrdcgiDebug
+ * 
+ *  Set/unsets debugging
+ */
+void rrdcgiDebug(int level, int where);
+
+/* rrdcgiInit
+ *
+ *  Reads in variables set via POST or stdin.
+ */
+s_cgi *rrdcgiInit (void);
+
+/* rrdcgiGetValue
+ *
+ *  Returns the value of the specified variable or NULL if it's empty
+ *  or doesn't exist.
+ */
+char *rrdcgiGetValue (s_cgi *parms, const char *name);
+
+/* rrdcgiFreeList
+ *
+ * Frees a list as returned by rrdcgiGetVariables()
+ */
+void rrdcgiFreeList (char **list);
+
+/* rrdcgiFree
+ *
+ * Frees the internal data structures
+ */
+void rrdcgiFree (s_cgi *parms);
+
+/*  rrdcgiReadVariables()
+ *
+ *  Read from stdin if no string is provided via CGI.  Variables that
+ *  doesn't have a value associated with it doesn't get stored.
+ */
+s_var **rrdcgiReadVariables(void);
+
+
+int rrdcgiDebugLevel = 0;
+int rrdcgiDebugStderr = 1;
+char *rrdcgiHeaderString = NULL;
+char *rrdcgiType = NULL;
 
 /* rrd interface to the variable functions {put,get}var() */
 char* rrdgetvar(long argc, const char **args);
@@ -294,8 +355,8 @@ int main(int argc, char *argv[]) {
        }
 
        if (!filter) {
-               cgiDebug(0,0);
-               cgiArg = cgiInit();
+               rrdcgiDebug(0,0);
+               rrdcgiArg = rrdcgiInit();
                server_url = getenv("SERVER_URL");
        }
 
@@ -588,7 +649,7 @@ char* rrdstrip(char *buf) {
 
 char* cgigetq(long argc, const char **args){
   if (argc>= 1){
-    char *buf = rrdstrip(cgiGetValue(cgiArg,args[0]));
+    char *buf = rrdstrip(rrdcgiGetValue(rrdcgiArg,args[0]));
     char *buf2;
     char *c,*d;
     int  qc=0;
@@ -635,7 +696,7 @@ char* cgigetqp(long argc, const char **args){
                 return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]");
         }
 
-        buf = rrdstrip(cgiGetValue(cgiArg, args[0]));
+        buf = rrdstrip(rrdcgiGetValue(rrdcgiArg, args[0]));
     if (!buf)
         {
                 return NULL;
@@ -682,7 +743,7 @@ char* cgigetqp(long argc, const char **args){
 
 char* cgiget(long argc, const char **args){
   if (argc>= 1)
-    return rrdstrip(cgiGetValue(cgiArg,args[0]));
+    return rrdstrip(rrdcgiGetValue(rrdcgiArg,args[0]));
   else
     return stralloc("[ERROR: not enough arguments for RRD::CV]");
 }
@@ -1048,3 +1109,293 @@ http_time(time_t *now) {
         strftime(buf,sizeof(buf),"%a, %d %b %Y %H:%M:%S GMT",tmptime);
         return(buf);
 }
+
+void rrdcgiHeader(void)
+{
+    if (rrdcgiType)
+       printf ("Content-type: %s\n", rrdcgiType);
+    else
+       printf ("Content-type: text/html\n");
+    if (rrdcgiHeaderString)
+       printf ("%s", rrdcgiHeaderString);
+    printf ("\n");
+}
+
+void rrdcgiDebug(int level, int where)
+{
+    if (level > 0)
+       rrdcgiDebugLevel = level;
+    else
+       rrdcgiDebugLevel = 0;
+    if (where)
+       rrdcgiDebugStderr = 0;
+    else
+       rrdcgiDebugStderr = 1;
+}
+
+char *rrdcgiDecodeString(char *text)
+{
+    char *cp, *xp;
+
+    for (cp=text,xp=text; *cp; cp++) {
+       if (*cp == '%') {
+           if (strchr("0123456789ABCDEFabcdef", *(cp+1))
+               && strchr("0123456789ABCDEFabcdef", *(cp+2))) {
+               if (islower(*(cp+1)))
+                   *(cp+1) = toupper(*(cp+1));
+               if (islower(*(cp+2)))
+                   *(cp+2) = toupper(*(cp+2));
+               *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16
+                   + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0');
+               xp++;cp+=2;
+           }
+       } else {
+           *(xp++) = *cp;
+       }
+    }
+    memset(xp, 0, cp-xp);
+    return text;
+}
+
+/*  rrdcgiReadVariables()
+ *
+ *  Read from stdin if no string is provided via CGI.  Variables that
+ *  doesn't have a value associated with it doesn't get stored.
+ */
+s_var **rrdcgiReadVariables(void)
+{
+    int length;
+    char *line = NULL;
+    int numargs;
+    char *cp, *ip, *esp, *sptr;
+    s_var **result;
+    int i, k, len;
+    char tmp[101];
+
+    cp = getenv("REQUEST_METHOD");
+    ip = getenv("CONTENT_LENGTH");
+
+    if (cp && !strcmp(cp, "POST")) {
+       if (ip) {
+           length = atoi(ip);
+           if ((line = (char *)malloc (length+2)) == NULL)
+               return NULL;
+           fgets(line, length+1, stdin);
+       } else
+           return NULL;
+    } else if (cp && !strcmp(cp, "GET")) {
+       esp = getenv("QUERY_STRING");
+       if (esp && strlen(esp)) {
+           if ((line = (char *)malloc (strlen(esp)+2)) == NULL)
+               return NULL;
+           sprintf (line, "%s", esp);
+       } else
+           return NULL;
+    } else {
+        length = 0;
+       printf ("(offline mode: enter name=value pairs on standard input)\n");
+       memset (tmp, 0, sizeof(tmp));
+       while((cp = fgets (tmp, 100, stdin)) != NULL) {
+           if (strlen(tmp)) {
+               if (tmp[strlen(tmp)-1] == '\n')
+                   tmp[strlen(tmp)-1] = '&';
+               if (length) {
+                   length += strlen(tmp);
+                   len = (length+1) * sizeof(char);
+                   if ((line = (char *)realloc (line, len)) == NULL)
+                       return NULL;
+                   strcat (line, tmp);
+               } else {
+                   length = strlen(tmp);
+                   len = (length+1) * sizeof(char);
+                   if ((line = (char *)malloc (len)) == NULL)
+                       return NULL;
+                   memset (line, 0, len);
+                   strcpy (line, tmp);
+               }
+           }
+           memset (tmp, 0, sizeof(tmp));
+       }
+       if (!line)
+           return NULL;
+       if (line[strlen(line)-1] == '&')
+           line[strlen(line)-1] = '\0';
+    }
+
+    /*
+     *  From now on all cgi variables are stored in the variable line
+     *  and look like  foo=bar&foobar=barfoo&foofoo=
+     */
+
+    if (rrdcgiDebugLevel > 0) {
+       if (rrdcgiDebugStderr)
+           fprintf (stderr, "Received cgi input: %s\n", line);
+       else
+           printf ("<b>Received cgi input</b><br>\n<pre>\n--\n%s\n--\n</pre>\n\n", line);
+    }
+
+    for (cp=line; *cp; cp++)
+       if (*cp == '+')
+           *cp = ' ';
+
+    if (strlen(line)) {
+       for (numargs=1,cp=line; *cp; cp++)
+           if (*cp == '&') numargs++;
+    } else
+       numargs = 0;
+    if (rrdcgiDebugLevel > 0) {
+       if (rrdcgiDebugStderr)
+           fprintf (stderr, "%d cgi variables found.\n", numargs);
+       else
+           printf ("%d cgi variables found.<br>\n", numargs);
+    }
+
+    len = (numargs+1) * sizeof(s_var *);
+    if ((result = (s_var **)malloc (len)) == NULL)
+       return NULL;
+    memset (result, 0, len);
+
+    cp = line;
+    i=0;
+    while (*cp) {
+       if ((ip = (char *)strchr(cp, '&')) != NULL) {
+           *ip = '\0';
+       }else
+           ip = cp + strlen(cp);
+
+       if ((esp=(char *)strchr(cp, '=')) == NULL) {
+           cp = ++ip;
+           continue;
+       }
+
+       if (!strlen(esp)) {
+           cp = ++ip;
+           continue;
+       }
+
+       if (i<numargs) {
+
+           /* try to find out if there's already such a variable */
+           for (k=0; k<i && (strncmp (result[k]->name,cp, esp-cp) || !(strlen (result[k]->name) == esp-cp)); k++);
+
+           if (k == i) {       /* No such variable yet */
+               if ((result[i] = (s_var *)malloc(sizeof(s_var))) == NULL)
+                   return NULL;
+               if ((result[i]->name = (char *)malloc((esp-cp+1) * sizeof(char))) == NULL)
+                   return NULL;
+               memset (result[i]->name, 0, esp-cp+1);
+               strncpy(result[i]->name, cp, esp-cp);
+               cp = ++esp;
+               if ((result[i]->value = (char *)malloc((ip-esp+1) * sizeof(char))) == NULL)
+                   return NULL;
+               memset (result[i]->value, 0, ip-esp+1);
+               strncpy(result[i]->value, cp, ip-esp);
+               result[i]->value = rrdcgiDecodeString(result[i]->value);
+               if (rrdcgiDebugLevel) {
+                   if (rrdcgiDebugStderr)
+                       fprintf (stderr, "%s: %s\n", result[i]->name, result[i]->value);
+                   else
+                       printf ("<h3>Variable %s</h3>\n<pre>\n%s\n</pre>\n\n", result[i]->name, result[i]->value);
+               }
+               i++;
+           } else {    /* There is already such a name, suppose a mutiple field */
+               cp = ++esp;
+               len = (strlen(result[k]->value)+(ip-esp)+2) * sizeof (char);
+               if ((sptr = (char *)malloc(len)) == NULL)
+                   return NULL;
+               memset (sptr, 0, len);
+               sprintf (sptr, "%s\n", result[k]->value);
+               strncat(sptr, cp, ip-esp);
+               free(result[k]->value);
+               result[k]->value = rrdcgiDecodeString (sptr);
+           }
+       }
+       cp = ++ip;
+    }
+    return result;
+}
+
+/*  rrdcgiInit()
+ *
+ *  Read from stdin if no string is provided via CGI.  Variables that
+ *  doesn't have a value associated with it doesn't get stored.
+ */
+s_cgi *rrdcgiInit(void)
+{
+    s_cgi *res;
+    s_var **vars;
+
+    vars = rrdcgiReadVariables();
+
+    if (!vars)
+       return NULL;
+
+    if ((res = (s_cgi *)malloc (sizeof (s_cgi))) == NULL)
+       return NULL;
+    res->vars = vars;
+
+    return res;
+}
+
+char *rrdcgiGetValue(s_cgi *parms, const char *name)
+{
+    int i;
+
+    if (!parms || !parms->vars)
+       return NULL;
+    for (i=0;parms->vars[i]; i++)
+       if (!strcmp(name,parms->vars[i]->name)) {
+           if (rrdcgiDebugLevel > 0) {
+               if (rrdcgiDebugStderr)
+                   fprintf (stderr, "%s found as %s\n", name, parms->vars[i]->value);
+               else
+                   printf ("%s found as %s<br>\n", name, parms->vars[i]->value);
+           }
+           return parms->vars[i]->value;
+       }
+    if (rrdcgiDebugLevel) {
+       if (rrdcgiDebugStderr)
+           fprintf (stderr, "%s not found\n", name);
+       else
+           printf ("%s not found<br>\n", name);
+    }
+    return NULL;
+}
+
+void rrdcgiFreeList (char **list)
+{
+    int i;
+
+    for (i=0; list[i] != NULL; i++)
+       free (list[i]);
+       free (list);
+}
+
+void rrdcgiFree (s_cgi *parms)
+{
+    int i;
+
+    if (!parms)
+       return;
+    if (parms->vars) {
+               for (i=0;parms->vars[i]; i++) {
+                       if (parms->vars[i]->name)
+                               free (parms->vars[i]->name);
+                       if (parms->vars[i]->value)
+                               free (parms->vars[i]->value);
+           free (parms->vars[i]);
+               }
+               free (parms->vars);
+    }
+    free (parms);
+
+    if (rrdcgiHeaderString) {
+       free (rrdcgiHeaderString);
+       rrdcgiHeaderString = NULL;
+    }
+    if (rrdcgiType) {
+       free (rrdcgiType);
+       rrdcgiType = NULL;
+    }
+}
+