* 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 e2d5c6a..9f59bb7 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 0c872be..b2dfba2 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 6bee6b7..d029600 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 2daa5a5..17a6b16 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;
+    }
+}
+