Back to index

courier  0.68.2
cgi.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2011 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 /*
00007 */
00008 #include      "cgi.h"
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <ctype.h>
00013 #include      <errno.h>
00014 
00015 #if    HAVE_UNISTD_H
00016 #include      <unistd.h>
00017 #endif
00018 
00019 #if    TIME_WITH_SYS_TIME
00020 #include      <sys/time.h>
00021 #include      <time.h>
00022 #else
00023 #if    HAVE_SYS_TIME_H
00024 #include      <sys/time.h>
00025 #else
00026 #include      <time.h>
00027 #endif
00028 #endif
00029 
00030 #ifndef       CGIMAXARG
00031 #define       CGIMAXARG     500000
00032 #endif
00033 
00034 #ifndef       CGIMAXFORMDATAARG
00035 #define       CGIMAXFORMDATAARG    2000000
00036 #endif
00037 
00038 #if CGIMAXARG < 256
00039 #error CGIMAXARG too small
00040 #endif
00041 
00042 #if CGIMAXFORMDATAARG < 1024
00043 #error CGIMAXFORMDATAARG too small
00044 #endif
00045 
00046 #if    CGIFORMDATA
00047 
00048 #include      <fcntl.h>
00049 #include      <sys/types.h>
00050 #include      <sys/stat.h>
00051 #include      "rfc2045/rfc2045.h"
00052 
00053 static void cgi_formdata(unsigned long);
00054 
00055 #ifndef       HAVE_STRNCASECMP
00056 extern int strncasecmp(const char *, const char *, size_t);
00057 #endif
00058 
00059 static int cgiformfd;
00060 static char hascgiformfd=0;
00061 static struct rfc2045 *rfc2045p=0;
00062 
00063 #endif
00064 
00065 extern void error(const char *);
00066 
00067 static void enomem()
00068 {
00069        error("Out of memory.");
00070 }
00071 
00072 static char *cgi_args=0;
00073 
00074 struct cgi_arglist *cgi_arglist=0;
00075 
00076 static size_t cgi_maxarg()
00077 {
00078        const char *p=getenv("SQWEBMAIL_MAXARGSIZE");
00079        size_t n=0;
00080 
00081        if (p)
00082               n=atoi(p);
00083 
00084        if (n < CGIMAXARG)
00085               n=CGIMAXARG;
00086        return n;
00087 }
00088 
00089 static size_t cgi_maxformarg()
00090 {
00091        const char *p=getenv("SQWEBMAIL_MAXATTSIZE");
00092        size_t n=0;
00093 
00094        if (p)
00095               n=atoi(p);
00096 
00097        if (n < CGIMAXFORMDATAARG)
00098               n=CGIMAXFORMDATAARG;
00099        return n;
00100 }
00101 
00102 /*
00103 **     Set up CGI arguments.  Initializes cgi_arglist link list.
00104 **
00105 **     arg1<NUL>value1<NUL>arg2<NUL>value2<NUL> ... argn<NUL>valuen<NUL><NUL>
00106 */
00107 
00108 static void cgi_setup_1();
00109 
00110 void cgi_setup()
00111 {
00112 struct cgi_arglist *p;
00113 
00114        cgi_setup_1();
00115 
00116        if (cgi_arglist)
00117               cgi_arglist->prev=0;
00118 
00119        /* Initialize the prev pointer */
00120 
00121        for (p=cgi_arglist; p; p=p->next)
00122               if (p->next)
00123                      p->next->prev=p;
00124 }
00125 
00126 
00127 static void cgi_setup_1()
00128 {
00129 char   *p=getenv("REQUEST_METHOD"), *q, *r;
00130 char   *args;
00131 unsigned long cl;
00132 int    c;
00133 struct cgi_arglist *argp;
00134 
00135        if (p && strcmp(p, "GET") == 0)    /* This is a GET post */
00136        {
00137               args=getenv("QUERY_STRING");
00138               if (!args)    return;
00139               if (strlen(args) > cgi_maxarg())   enomem();
00140               cgi_args=malloc(strlen(args)+1);   /* Extra insurance */
00141               if (!cgi_args)       return;
00142               strcpy(cgi_args,args);
00143               args=cgi_args;
00144        }
00145        else if (p && strcmp(p, "POST") == 0)
00146        {
00147               args=getenv("CONTENT_TYPE");
00148               if (!args)    return;
00149 
00150 #if    CGIFORMDATA
00151 
00152               if (strncasecmp(args,"multipart/form-data;", 20) == 0)
00153               {
00154                      args=getenv("CONTENT_LENGTH");
00155                      if (!args)    return;
00156                      cl=atol(args);
00157                      if (cl > cgi_maxformarg())
00158                      {
00159                             printf("Content-Type: text/html\n\n");
00160                             printf("<html><body><h1>Attachment size (%ld MB) exceeds limit set by system administrator (%ld MB)</h1></body></html>\n",
00161                                    (long)(cl / (1024 * 1024)),
00162                                    (long)(cgi_maxformarg() / (1024 * 1024)));
00163                             fake_exit(1);
00164                      }
00165                      cgi_formdata(cl);
00166                      return;
00167               }
00168 #endif
00169 
00170               if (strncmp(args, "application/x-www-form-urlencoded", 33))
00171                      return;
00172               args=getenv("CONTENT_LENGTH");
00173               if (!args)    return;
00174               cl=atol(args);
00175               if (cl > cgi_maxarg())
00176               {
00177                      printf("Content-Type: text/html\n\n");
00178                      printf("<html><body><h1>Message size (%ld MB) exceeds limit set by system administrator (%ld MB)</h1></body></html>\n",
00179                             (long)(cl / (1024 * 1024)),
00180                             (long)(cgi_maxarg() / (1024 * 1024)));
00181                      fake_exit(1);
00182               }
00183        cgi_args=malloc(cl+1);      /* Extra insurance */
00184               if (!cgi_args)       return;
00185               q=cgi_args;
00186               while (cl)
00187               {
00188                      c=getchar();
00189                      if (c < 0)
00190                      {
00191                             free(cgi_args);
00192                             cgi_args=0;
00193                             return;
00194                      }
00195                      *q++=c;
00196                      --cl;
00197               }
00198               *q=0;
00199               args=cgi_args;
00200        }
00201        else   return;
00202 
00203        q=args;
00204        while (*q)
00205        {
00206               argp=malloc(sizeof(*cgi_arglist));
00207               if (!argp)    enomem();
00208               argp->next=cgi_arglist;
00209               cgi_arglist=argp;
00210               argp->argname=q;
00211               argp->argvalue="";
00212               p=q;
00213               while (*q && *q != '&')
00214                      q++;
00215               if (*q)       *q++=0;
00216               if ((r=strchr(p, '=')) != 0)
00217               {
00218                      *r++='\0';
00219                      argp->argvalue=r;
00220                      cgiurldecode(r);
00221               }
00222               cgiurldecode(p);
00223        }
00224 }
00225 
00226 static char *cgiurlencode_common(const char *buf, const char *punct)
00227 {
00228 char   *newbuf=0;
00229 size_t cnt=0;
00230 int    pass;
00231 const char *p;
00232 static const char hex[]="0123456789ABCDEF";
00233 
00234        for (pass=0; pass<2; pass++)
00235        {
00236               if (pass && (newbuf=malloc(cnt+1)) == 0)  enomem();
00237               cnt=0;
00238               for (p=buf; *p; p++)
00239               {
00240                      if (strchr(punct, *p) || *p < 32 || *p >= 127)
00241                      {
00242                             if (pass)
00243                             {
00244                                    newbuf[cnt]='%';
00245                                    newbuf[cnt+1]=hex[
00246                                           ((int)(unsigned char)*p) / 16];
00247                                    newbuf[cnt+2]=hex[ *p & 15 ];
00248                             }
00249                             cnt += 3;
00250                             continue;
00251                      }
00252                      if (pass)
00253                             newbuf[cnt]= *p == ' ' ? '+':*p;
00254                      ++cnt;
00255               }
00256        }
00257        newbuf[cnt]=0;
00258        return (newbuf);
00259 }
00260 
00261 char *cgiurlencode(const char *buf)
00262 {
00263        return (cgiurlencode_common(buf, "\"?;<>&=/:%@+#"));
00264 }
00265 
00266 char *cgiurlencode_noamp(const char *buf)
00267 {
00268        return (cgiurlencode_common(buf, "\"?<>=/:%@+#"));
00269 }
00270 
00271 char *cgiurlencode_noeq(const char *buf)
00272 {
00273        return (cgiurlencode_common(buf, "\"?;<>&/:%@+#"));
00274 }
00275 
00276 void cgi_cleanup()
00277 {
00278 #if    CGIFORMDATA
00279 
00280        if (hascgiformfd)
00281        {
00282               close(cgiformfd);
00283               hascgiformfd=0;
00284        }
00285 #endif
00286 
00287 }
00288 
00289 const char *cgi(const char *arg)
00290 {
00291 struct cgi_arglist *argp;
00292 
00293        for (argp=cgi_arglist; argp; argp=argp->next)
00294               if (strcmp(argp->argname, arg) == 0)
00295                      return (argp->argvalue);
00296        return ("");
00297 }
00298 
00299 char *cgi_multiple(const char *arg, const char *sep)
00300 {
00301 struct cgi_arglist *argp;
00302 size_t l=1;
00303 char   *buf;
00304 
00305        for (argp=cgi_arglist; argp; argp=argp->next)
00306               if (strcmp(argp->argname, arg) == 0)
00307                      l += strlen(argp->argvalue)+strlen(sep);
00308 
00309        buf=malloc(l);
00310        if (!buf)     return(0);
00311        *buf=0;
00312 
00313        /*
00314        ** Because the cgi list is build from the tail end up, we go backwards
00315        ** now, so that we return options in the same order they were selected.
00316        */
00317 
00318        argp=cgi_arglist;
00319        while (argp && argp->next)
00320               argp=argp->next;
00321 
00322        for (; argp; argp=argp->prev)
00323               if (strcmp(argp->argname, arg) == 0)
00324               {
00325                      if (*buf)     strcat(buf, sep);
00326                      strcat(buf, argp->argvalue);
00327               }
00328        return (buf);
00329 }
00330 
00331 static char *nybble(char *p, int *n)
00332 {
00333        if ( *p >= '0' && *p <= '9')
00334               (*n) = (*n) * 16 + (*p++ - '0');
00335        else if ( *p >= 'A' && *p <= 'F')
00336               (*n) = (*n) * 16 + (*p++ - 'A' + 10);
00337        else if ( *p >= 'a' && *p <= 'f')
00338               (*n) = (*n) * 16 + (*p++ - 'a' + 10);
00339        return (p);
00340 }
00341 
00342 void cgiurldecode(char *q)
00343 {
00344 char   *p=q;
00345 int    c;
00346 
00347        while (*q)
00348        {
00349               if (*q == '+')
00350               {
00351                      *p++=' ';
00352                      q++;
00353                      continue;
00354               }
00355               if (*q != '%')
00356               {
00357                      *p++=*q++;
00358                      continue;
00359               }
00360               ++q;
00361               c=0;
00362               q=nybble(q, &c);
00363               q=nybble(q, &c);
00364 
00365               if (c && c != '\r')
00366                      /* Ignore CRs we get in TEXTAREAS */
00367                      *p++=c;
00368        }
00369        *p++=0;
00370 }
00371 
00372 void cgi_put(const char *cginame, const char *cgivalue)
00373 {
00374 struct cgi_arglist *argp;
00375 
00376        for (argp=cgi_arglist; argp; argp=argp->next)
00377               if (strcmp(argp->argname, cginame) == 0)
00378               {
00379                      argp->argvalue=cgivalue;
00380                      return;
00381               }
00382 
00383        argp=malloc(sizeof(*cgi_arglist));
00384        if (!argp)    enomem();
00385        argp->next=cgi_arglist;
00386        argp->prev=0;
00387        if (argp->next)
00388               argp->next->prev=argp;
00389        cgi_arglist=argp;
00390        argp->argname=cginame;
00391        argp->argvalue=cgivalue;
00392 }
00393 
00394 #if    CGIFORMDATA
00395 
00396 /**************************************************************************/
00397 
00398 /* multipart/formdata decoding */
00399 
00400 static char *disposition_name=NULL, *disposition_filename=NULL;
00401 
00402 static char *formargbuf;
00403 static char *formargptr;
00404 
00405 static int save_formdata(const char *p, size_t l, void *miscptr)
00406 {
00407        memcpy(formargptr, p, l);
00408        formargptr += l;
00409        return (0);
00410 }
00411 
00412 static void cgiformdecode(struct rfc2045 *p, struct rfc2045id *a, void *b)
00413 {
00414 off_t start_pos, end_pos, start_body;
00415 char   buf[512];
00416 int    n;
00417 off_t  dummy;
00418 
00419        a=a;
00420        b=b;
00421 
00422        if (disposition_name)
00423               free(disposition_name);
00424        if (disposition_filename)
00425               free(disposition_filename);
00426 
00427        if (rfc2231_udecodeDisposition(p, "name", NULL, &disposition_name) < 0)
00428               disposition_name=NULL;
00429 
00430        if (rfc2231_udecodeDisposition(p, "filename", NULL,
00431                                    &disposition_filename) < 0)
00432               disposition_filename=NULL;
00433 
00434        if (!p->content_disposition
00435            || strcmp(p->content_disposition, "form-data"))     return;
00436 
00437        if (!disposition_name || !*disposition_name)     return;
00438 
00439        if (!disposition_filename || !*disposition_filename)
00440        {
00441               rfc2045_mimepos(p, &start_pos, &end_pos, &start_body,
00442                      &dummy, &dummy);
00443 
00444               if (lseek(cgiformfd, start_body, SEEK_SET) == -1)
00445                      enomem();
00446 
00447               formargbuf=malloc(end_pos - start_body+1);
00448               if (!formargbuf)     enomem();
00449               formargptr=formargbuf;
00450 
00451               rfc2045_cdecode_start(p, &save_formdata, 0);
00452               while (start_body < end_pos)
00453               {
00454                      n=sizeof(buf);
00455                      if (n > end_pos - start_body)
00456                             n=end_pos-start_body;
00457                      n=read(cgiformfd, buf, n);
00458                      if (n <= 0)   enomem();
00459                      rfc2045_cdecode(p, buf, n);
00460                      start_body += n;
00461               }
00462               rfc2045_cdecode_end(p);
00463 
00464               *formargptr=0;
00465               {
00466                      char   *name=strdup(disposition_name);
00467                      char   *value=strdup(formargbuf);
00468                      char   *p, *q;
00469 
00470                      /* Just like for GET/POSTs, strip CRs. */
00471 
00472                      for (p=q=value; *p; p++)
00473                      {
00474                             if (*p == '\r')      continue;
00475                             *q++ = *p;
00476                      }
00477                      *q++='\0';
00478                      cgi_put(name, value);
00479               }
00480               free(formargbuf);
00481        }
00482 }
00483 
00484 static const char *cgitempdir="/tmp";
00485 
00486 void cgiformdatatempdir(const char *p)
00487 {
00488        cgitempdir=p;
00489 }
00490 
00491 static void cgiformfdw(const char *p, size_t n)
00492 {
00493        while (n)
00494        {
00495        int    k=write(cgiformfd, p, n);
00496 
00497               if (k <= 0)   enomem();
00498               p += k;
00499               n -= k;
00500        }
00501 }
00502 
00503 static void cgi_formdata(unsigned long contentlength)
00504 {
00505 char   pidbuf[MAXLONGSIZE];
00506 char   timebuf[MAXLONGSIZE];
00507 char   cntbuf[MAXLONGSIZE];
00508 time_t t;
00509 unsigned long cnt;
00510 int    n;
00511 char   *filename, *p;
00512 
00513 static const char fakeheader[]="MIME-Version: 1.0\nContent-Type: ";
00514 char   buf[BUFSIZ];
00515 
00516        sprintf(pidbuf, "%lu", (unsigned long)getpid());
00517        time(&t);
00518        sprintf(timebuf, "%lu", (unsigned long)t);
00519        cnt=0;
00520 
00521        buf[sizeof(buf)-1]=0;
00522        if (gethostname(buf, sizeof(buf)-1) != 0)
00523               buf[0]='\0';
00524 
00525        do
00526        {
00527               sprintf(cntbuf, "%lu", (unsigned long)cnt);
00528               filename=malloc(strlen(pidbuf)+strlen(timebuf)+strlen(cntbuf)
00529                             +strlen(cgitempdir)+strlen(buf)+10);
00530               if (!filename)       enomem();
00531               sprintf(filename, "%s/%s.%s_%s.%s", cgitempdir,
00532                             timebuf, pidbuf, cntbuf, buf);
00533               cgiformfd=open(filename, O_RDWR | O_CREAT | O_EXCL, 0644);
00534        } while (cgiformfd < 0);
00535        unlink(filename);    /* !!!MUST WORK!!! */
00536        hascgiformfd=1;
00537        p=getenv("CONTENT_TYPE");
00538        free(filename);
00539        cgiformfdw(fakeheader, strlen(fakeheader));
00540        cgiformfdw(p, strlen(p));
00541        cgiformfdw("\n\n", 2);
00542 
00543        clearerr(stdin);
00544 
00545        while (contentlength)
00546        {
00547               n=sizeof(buf);
00548               if (n > contentlength)      n=contentlength;
00549 
00550               n=fread(buf, 1, n, stdin);
00551               if (n <= 0)
00552                      enomem();
00553               cgiformfdw(buf, n);
00554               contentlength -= n;
00555        }
00556 
00557        rfc2045p=rfc2045_alloc();
00558        lseek(cgiformfd, 0L, SEEK_SET);
00559        while ((n=read(cgiformfd, buf, sizeof(buf))) > 0)
00560               rfc2045_parse(rfc2045p, buf, n);
00561        rfc2045_parse_partial(rfc2045p);
00562        rfc2045_decode(rfc2045p, &cgiformdecode, 0);
00563 
00564 }
00565 
00566 struct cgigetfileinfo {
00567        int (*start_file)(const char *, const char *, void *);
00568        int (*file)(const char *, size_t, void *);
00569        void (*end_file)(void *);
00570        size_t filenum;
00571        void *voidarg;
00572        } ;
00573 
00574 
00575 static void cgifiledecode(struct rfc2045 *p, struct rfc2045id *a, void *b)
00576 {
00577 off_t start_pos, end_pos, start_body;
00578 char   buf[512];
00579 int    n;
00580 struct cgigetfileinfo *c;
00581 off_t  dummy;
00582 
00583        a=a;
00584        c=(struct cgigetfileinfo *)b;
00585 
00586        if (c->filenum == 0) return;       /* Already retrieved this one. */
00587 
00588        if (disposition_name)
00589               free(disposition_name);
00590        if (disposition_filename)
00591               free(disposition_filename);
00592 
00593        if (rfc2231_udecodeDisposition(p, "name", NULL, &disposition_name) < 0
00594            ||
00595            rfc2231_udecodeDisposition(p, "filename", NULL,
00596                                    &disposition_filename) < 0)
00597        {
00598               disposition_name=disposition_filename=NULL;
00599               enomem();
00600        }
00601 
00602        if (!p->content_disposition
00603            || strcmp(p->content_disposition, "form-data"))     return;
00604 
00605        if (!*disposition_name)     return;
00606 
00607        if (!*disposition_filename) return;
00608 
00609        rfc2045_mimepos(p, &start_pos, &end_pos, &start_body,
00610                      &dummy, &dummy);
00611 
00612        if (start_body == end_pos)  /* NULL FILE */
00613                      return;
00614 
00615        if ( --c->filenum )  return;       /* Not this one */
00616 
00617        if ( (*c->start_file)(disposition_name, disposition_filename,
00618                            c->voidarg) )
00619               return;
00620 
00621        if (lseek(cgiformfd, start_body, SEEK_SET) == -1)
00622               enomem();
00623 
00624        rfc2045_cdecode_start(p, c->file, c->voidarg);
00625        while (start_body < end_pos)
00626        {
00627               n=sizeof(buf);
00628               if (n > end_pos - start_body)
00629                      n=end_pos-start_body;
00630               n=read(cgiformfd, buf, n);
00631               if (n <= 0)   enomem();
00632               rfc2045_cdecode(p, buf, n);
00633               start_body += n;
00634        }
00635        rfc2045_cdecode_end(p);
00636        (*c->end_file)(c->voidarg);
00637 }
00638 
00639 int cgi_getfiles( int (*start_file)(const char *, const char *, void *),
00640               int (*file)(const char *, size_t, void *),
00641               void (*end_file)(void *), size_t filenum, void *voidarg)
00642 {
00643        struct cgigetfileinfo gfi;
00644 
00645        gfi.start_file=start_file;
00646        gfi.file=file;
00647        gfi.end_file=end_file;
00648        gfi.filenum=filenum;
00649        gfi.voidarg=voidarg;
00650 
00651        if (rfc2045p) rfc2045_decode(rfc2045p, &cgifiledecode, &gfi);
00652        if (gfi.filenum)     return (-1);
00653        return (0);
00654 }
00655 
00656 #endif
00657 
00658 /* cookies */
00659 
00660 int cgi_set_cookie_url(struct cgi_set_cookie_info *cookie_info,
00661                      const char *url)
00662 {
00663        const char *p;
00664 
00665        if (cookie_info->domain)
00666               free(cookie_info->domain);
00667        if (cookie_info->path)
00668               free(cookie_info->domain);
00669 
00670        cookie_info->secure=0;
00671 
00672        if (strncmp(url, "https://", 8) == 0)
00673               cookie_info->secure=1;
00674 
00675        for (p=url; *p; p++)
00676        {
00677               if (*p == ':')
00678               {
00679                      url= ++p;
00680                      break;
00681               }
00682 
00683               if (*p == '/')
00684                      break;
00685        }
00686 
00687        if (strncmp(url, "//", 2) == 0)
00688        {
00689               p= url += 2;
00690 
00691               while (*url)
00692               {
00693                      if (*url == '/')
00694                             break;
00695                      ++url;
00696               }
00697 
00698               if ((cookie_info->domain=malloc(url-p+1)) == NULL)
00699                      return -1;
00700 
00701               memcpy(cookie_info->domain, p, url-p);
00702               cookie_info->domain[url-p]=0;
00703        }
00704 
00705        if ((cookie_info->path=strdup(url)) == NULL)
00706               return -1;
00707        return 0;
00708 }
00709 
00710 void cgi_set_cookies(struct cgi_set_cookie_info *cookies,
00711                    size_t n_cookies)
00712 {
00713        size_t i;
00714        const char *sep="";
00715 
00716        printf("Set-Cookie: ");
00717 
00718        for (i=0; i<n_cookies; i++, cookies++)
00719        {
00720               printf("%s%s=\"%s\"; ", sep, cookies->name, cookies->value);
00721               sep="; ";
00722 
00723               if (cookies->path)
00724                      printf("Path=\"%s\"; ", cookies->path);
00725 
00726               if (cookies->secure)
00727                      printf("Secure; ");
00728 
00729               if (cookies->age >= 0)
00730                      printf("Max-Age=%d; ", cookies->age);
00731               printf("Version=1");
00732        }
00733 
00734        printf("\n");
00735        fflush(stdout);
00736 }
00737 
00738 /*
00739 ** Parse Cookie: header
00740 **
00741 ** get_cookie_value() skips over a single cookie name=value, returning # of
00742 ** bytes, excluding quotes (if any), plus one more (for the trailing \0).
00743 **
00744 ** out_ptr, if not NULL, receives ptr to the next byte after name=value
00745 **
00746 ** out_value, if not NULL receives the cookie's value, excluding any quotes.
00747 */
00748 
00749 static size_t get_cookie_value(const char *ptr, const char **out_ptr,
00750                             char *out_value)
00751 {
00752        int in_quote=0;
00753        size_t cnt=1;
00754 
00755        while (*ptr)
00756        {
00757               if (!in_quote)
00758               {
00759                      if (*ptr == ';' || *ptr == ',' ||
00760                          isspace((int)(unsigned char)*ptr))
00761                             break;
00762               }
00763 
00764               if (*ptr == '"')
00765               {
00766                      in_quote= ~in_quote;
00767                      ++ptr;
00768                      continue;
00769               }
00770 
00771               if (out_value)
00772                      *out_value++ = *ptr;
00773               ++cnt;
00774               ++ptr;
00775        }
00776 
00777        if (out_value)
00778               *out_value=0;
00779 
00780        if (out_ptr)
00781               *out_ptr=ptr;
00782        return cnt;
00783 }
00784 
00785 /*
00786 ** Search for a cookie.
00787 **
00788 ** Returns NULL and sets errno=ENOENT, if cookie not found.
00789 **
00790 ** Returns malloc-ed buffer that holds the cookie's value (or NULL if
00791 ** malloc fails).
00792 */
00793 
00794 char *cgi_get_cookie(const char *cookie_name)
00795 {
00796        size_t cookie_name_len=strlen(cookie_name);
00797        const char *cookie=getenv("HTTP_COOKIE");
00798 
00799        if (!cookie)
00800               cookie="";
00801 
00802        while (*cookie)
00803        {
00804               if (isspace((int)(unsigned char)*cookie) ||
00805                   *cookie == ';' || *cookie == ',')
00806               {
00807                      ++cookie;
00808                      continue;
00809               }
00810 
00811               if (strncmp(cookie, cookie_name, cookie_name_len) == 0 &&
00812                   cookie[cookie_name_len] == '=')
00813               {
00814                      char *buf;
00815 
00816                      cookie += cookie_name_len;
00817                      ++cookie;
00818 
00819                      if ((buf=malloc(get_cookie_value(cookie, NULL, NULL)))
00820                          == NULL)
00821                      {
00822                             return NULL;
00823                      }
00824 
00825                      get_cookie_value(cookie, NULL, buf);
00826 
00827                      if (*buf == 0) /* Pretend not found */
00828                      {
00829                             free(buf);
00830                             errno=ENOENT;
00831                             return NULL;
00832                      }
00833 
00834                      return buf;
00835               }
00836 
00837               get_cookie_value(cookie, &cookie, NULL);
00838        }
00839 
00840        errno=ENOENT;
00841        return NULL;
00842 }