From be67fb36af7b40e2cb388a4d8a1f3cc0bdba90b2 Mon Sep 17 00:00:00 2001 From: oetiker Date: Sat, 12 Nov 2005 23:10:48 +0000 Subject: [PATCH] * integrate necessary cgi functionality into rrd_cgi.c so that libcgi is not required anymore ... -- D. Walsh * 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 | 47 +++--- doc/rrdbuild.pod | 23 --- src/Makefile.am | 5 +- src/rrd_cgi.c | 369 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 389 insertions(+), 55 deletions(-) diff --git a/configure.ac b/configure.ac index e2d5c6a..9f59bb7 100644 --- a/configure.ac +++ b/configure.ac @@ -78,6 +78,10 @@ char *strchr (), *strrchr (); # define rrd_realloc(a,b) realloc((a), (b)) #endif +#if NEED_MALLOC_MALLOC_H +# include +#endif + #if HAVE_MATH_H # include #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 ]], + [[malloc(1)]] + ), + [ AC_MSG_RESULT([nope, works out of the box]) ], + [ AC_LINK_IFELSE( + AC_LANG_PROGRAM( + [[#include + #include ]], + [[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 diff --git a/doc/rrdbuild.pod b/doc/rrdbuild.pod index 0c872be..b2dfba2 100644 --- a/doc/rrdbuild.pod +++ b/doc/rrdbuild.pod @@ -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 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 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 diff --git a/src/Makefile.am b/src/Makefile.am index 6bee6b7..d029600 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/rrd_cgi.c b/src/rrd_cgi.c index 2daa5a5..17a6b16 100644 --- a/src/rrd_cgi.c +++ b/src/rrd_cgi.c @@ -5,16 +5,19 @@ *****************************************************************************/ #include "rrd_tool.h" -#include -#include #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 ("Received cgi input
\n
\n--\n%s\n--\n
\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.
\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 (iname,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 ("

Variable %s

\n
\n%s\n
\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
\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
\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; + } +} + -- 2.30.2