1 /*
2 ** Copyright (c) 2002 D. Richard Hipp
3 **
4 ** This program is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2 of the License, or (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ** General Public License for more details.
13 **
14 ** You should have received a copy of the GNU General Public
15 ** License along with this library; if not, write to the
16 ** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 ** Boston, MA  02111-1307, USA.
18 **
19 ** Author contact information:
20 **   drh@hwaci.com
21 **   http://www.hwaci.com/drh/
22 **
23 *******************************************************************************
24 **
25 ** This file contains C functions and procedures that provide useful
26 ** services to CGI programs.  There are procedures for parsing and
27 ** dispensing QUERY_STRING parameters and cookies, the "mprintf()"
28 ** formatting function and its cousins, and routines to encode and
29 ** decode strings in HTML or HTTP.
30 */
31 #include <config.h>
32 #include <ctype.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <time.h>
37 #include <sys/times.h>
38 #include <sys/time.h>
39 #include <sys/wait.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <sys/select.h>
43 #include <unistd.h>
44 #include "cgi.h"
45 
46 #if INTERFACE
47 /*
48 ** Shortcuts for cgi_parameter.  P("x") returns the value of query parameter
49 ** or cookie "x", or NULL if there is no such parameter or cookie.  PD("x","y")
50 ** does the same except "y" is returned in place of NULL if there is not match.
51 */
52 #define P(x)        cgi_parameter((x),0)
53 #define PD(x,y)     cgi_parameter((x),(y))
54 #define QP(x)       quotable_string(cgi_parameter((x),0))
55 #define QPD(x,y)    quotable_string(cgi_parameter((x),(y)))
56 
57 #endif /* INTERFACE */
58 
59 /*
60 ** The body of the HTTP reply text is stored here.
61 */
62 static int nAllocTxt = 0; /* Amount of space allocated for HTTP reply text */
63 static int nUsedTxt = 0;  /* Amount of space actually used */
64 static char *zTxt = 0;    /* Pointer to malloced space */
65 
66 /*
67 ** Append reply content to what already exists.  Return a pointer
68 ** to the start of the appended text.
69 */
cgi_append_content(const char * zData,int nAmt)70 const char *cgi_append_content(const char *zData, int nAmt){
71   if( nUsedTxt+nAmt >= nAllocTxt ){
72     nAllocTxt = nUsedTxt*2 + nAmt + 1000;
73     zTxt = realloc( zTxt, nAllocTxt );
74     if( zTxt==0 ) exit(1);
75   }
76   memcpy(&zTxt[nUsedTxt], zData, nAmt);
77   nUsedTxt += nAmt;
78   return &zTxt[nUsedTxt-nAmt];
79 }
80 
81 /*
82 ** Reset the HTTP reply text to be an empty string.
83 */
cgi_reset_content(void)84 void cgi_reset_content(void){
85   nUsedTxt = 0;
86   g.zLinkURL = 0;
87 }
88 
89 /*
90 ** Return a pointer to the HTTP reply text.  The text is reset
91 */
cgi_extract_content(int * pnAmt)92 char *cgi_extract_content(int *pnAmt){
93   char *z;
94   *pnAmt = nUsedTxt;
95   if( zTxt ){
96     zTxt[nUsedTxt] = 0;
97   }
98   z = zTxt;
99   zTxt = 0;
100   nAllocTxt = 0;
101   nUsedTxt = 0;
102   return z;
103 }
104 
105 /*
106 ** Additional information used to form the HTTP reply
107 */
108 static char *zContentType = "text/html"; /* Content type of the reply */
109 static char *zReplyStatus = "OK";        /* Reply status description */
110 static int iReplyStatus = 200;           /* Reply status code */
111 static char *zExtraHeader = 0;     /* Extra header text */
112 static int fullHttpReply = 0;      /* True for a full-blown HTTP header */
113 static const char *zLogFile = 0;   /* Name of the log file */
114 static const char *zLogArg = 0;    /* Argument to the log message */
115 
116 /*
117 ** Set the reply content type
118 */
cgi_set_content_type(const char * zType)119 void cgi_set_content_type(const char *zType){
120   zContentType = mprintf("%s", zType);
121 }
122 
123 /*
124 ** Set the reply status code
125 */
cgi_set_status(int iStat,const char * zStat)126 void cgi_set_status(int iStat, const char *zStat){
127   zReplyStatus = mprintf("%s", zStat);
128   iReplyStatus = iStat;
129 }
130 
131 /*
132 ** Append text to the header of an HTTP reply
133 */
cgi_append_header(const char * zLine)134 void cgi_append_header(const char *zLine){
135   if( zExtraHeader ){
136     zExtraHeader = mprintf("%z%s", zExtraHeader, zLine);
137   }else{
138     zExtraHeader = mprintf("%s", zLine);
139   }
140 }
141 
142 /*
143 ** Set a cookie.
144 **
145 ** Zero lifetime implies a session cookie.
146 */
cgi_set_cookie(const char * zName,const char * zValue,const char * zPath,int lifetime)147 void cgi_set_cookie(
148   const char *zName,    /* Name of the cookie */
149   const char *zValue,   /* Value of the cookie.  Automatically escaped */
150   const char *zPath,    /* Path cookie applies to.  NULL means "/" */
151   int lifetime          /* Expiration of the cookie in seconds */
152 ){
153   char *zCookie;
154   if( zPath==0 ) zPath = "/";
155   if( lifetime>0 ){
156 		lifetime += (int)time(0);
157     zCookie = mprintf("Set-Cookie: %s=%t; Path=%s; expires=%s; Version=1\r\n",
158                       zName, zValue, zPath, cgi_rfc822_datestamp(lifetime));
159   }else{
160     zCookie = mprintf("Set-Cookie: %s=%t; Path=%s; Version=1\r\n",
161                       zName, zValue, zPath);
162   }
163   cgi_append_header(zCookie);
164   free(zCookie);
165 }
166 
167 /*
168 ** This routine sets up the name of a logfile and an argument to the
169 ** log message.  The log message is written when cgi_reply() is invoked.
170 */
cgi_logfile(const char * zFile,const char * zArg)171 void cgi_logfile(const char *zFile, const char *zArg){
172   if( zFile ) zLogFile = zFile;
173   zLogArg = zArg;
174 }
175 
cgi_add_etag(char * zTxt,int nLen)176 static char *cgi_add_etag(char *zTxt, int nLen){
177   MD5Context ctx;
178   unsigned char digest[16];
179   int i, j;
180   char zETag[64];
181 
182   MD5Init(&ctx);
183   MD5Update(&ctx,(unsigned char *)zTxt,(unsigned int)nLen);
184   MD5Final(digest,&ctx);
185   for(j=i=0; i<16; i++,j+=2){
186     bprintf(&zETag[j],sizeof(zETag)-j,"%02x",(int)digest[i]);
187   }
188   cgi_append_header( mprintf("ETag: %s\r\n", zETag) );
189   return strdup(zETag);
190 }
191 
192 /*
193 ** Do some cache control stuff. First, we generate an ETag and include it in
194 ** the response headers. Second, we do whatever is necessary to determine if
195 ** the request was asking about caching and whether we need to send back the
196 ** response body. If we shouldn't send a body, return non-zero.
197 **
198 ** Currently, we just check the ETag against any If-None-Match header.
199 **
200 ** FIXME: In some cases (attachments, file contents) we could check
201 ** If-Modified-Since headers and always include Last-Modified in responses.
202 */
check_cache_control(void)203 static int check_cache_control(void){
204   /* FIXME: there's some gotchas wth cookies and some headers. */
205   char *zETag = cgi_add_etag(zTxt,nUsedTxt);
206   char *zMatch = getenv("HTTP_IF_NONE_MATCH");
207 
208   if( zETag!=0 && zMatch!=0 ) {
209     char *zBuf = strdup(zMatch);
210     if( zBuf!=0 ){
211       char *zTok = 0;
212       char *zPos;
213       for( zTok = strtok_r(zBuf, ",\"",&zPos);
214            zTok && strcasecmp(zTok,zETag);
215            zTok =  strtok_r(0, ",\"",&zPos)){}
216       free(zBuf);
217       if(zTok) return 1;
218     }
219   }
220 
221   return 0;
222 }
223 
224 /*
225 ** Do a normal HTTP reply
226 */
cgi_reply(void)227 void cgi_reply(void){
228   FILE *log;
229   if( iReplyStatus<=0 ){
230     iReplyStatus = 200;
231     zReplyStatus = "OK";
232   }
233 
234   if( iReplyStatus==200 && check_cache_control() ) {
235     /* change the status to "unchanged" and we can skip sending the
236     ** actual response body. Obviously we only do this when we _have_ a
237     ** body (code 200).
238     */
239     iReplyStatus = 304;
240     zReplyStatus = "Not Modified";
241   }
242 
243   if( fullHttpReply ){
244     printf("HTTP/1.0 %d %s\r\n", iReplyStatus, zReplyStatus);
245     printf("Date: %s\r\n", cgi_rfc822_datestamp(time(0)));
246     printf("Connection: close\r\n");
247   }else{
248     printf("Status: %d %s\r\n", iReplyStatus, zReplyStatus);
249   }
250 
251   if( zExtraHeader ){
252     printf("%s", zExtraHeader);
253   }
254 
255   if( g.isConst ){
256     /* constant means that the input URL will _never_ generate anything
257     ** else. In the case of attachments, the contents won't change because
258     ** an attempt to change them generates a new attachment number. In the
259     ** case of most /getfile calls for specific versions, the only way the
260     ** content changes is if someone breaks the SCM. And if that happens, a
261     ** stale cache is the least of the problem. So we provide an Expires
262     ** header set to a reasonable period (default: one week).
263     */
264     time_t expires = time(0) + atoi(db_config("constant_expires","604800"));
265     printf( "Expires: %s\r\n", cgi_rfc822_datestamp(expires));
266   }
267 
268   if( g.isAnon ){
269     printf("Cache-control: public\r\n");
270   }else{
271     /* Content intended for logged in users should only be cached in
272     ** the browser, not some shared location.
273     */
274     printf("Cache-control: private\r\n");
275   }
276 
277 #if CVSTRAC_I18N
278   printf( "Content-Type: %s; charset=%s\r\n", zContentType, nl_langinfo(CODESET));
279 #else
280   printf( "Content-Type: %s; charset=ISO-8859-1\r\n", zContentType);
281 #endif
282 
283   if( iReplyStatus != 304 ) {
284     printf( "Content-Length: %d\r\n", nUsedTxt );
285   }
286   printf("\r\n");
287   if( zTxt && iReplyStatus != 304 ){
288     fwrite(zTxt, 1, nUsedTxt, stdout);
289   }
290   if( zLogFile && (log = fopen(zLogFile,"a"))!=0 ){
291     time_t now;
292     struct tm *pTm;
293     const char *zPath;
294     const char *zAddr;
295     struct tms sTms;
296     double rScale;
297     char zDate[200];
298 
299     if( zLogArg==0 ) zLogArg = "*";
300     zPath = getenv("REQUEST_URI");
301     if( zPath==0 ) zPath = "/";
302     zAddr = getenv("REMOTE_ADDR");
303     if( zAddr==0 ) zAddr = "*";
304     time(&now);
305     pTm = localtime(&now);
306     strftime(zDate, sizeof(zDate), "%Y-%m-%d %H:%M:%S", pTm);
307     fprintf(log, "%s %s %s %d %s", zDate, zAddr, zPath, iReplyStatus,zLogArg);
308     times(&sTms);
309     rScale = 1.0/(double)sysconf(_SC_CLK_TCK);
310     fprintf(log, " %g %g %g %g\n",
311       rScale*sTms.tms_utime,
312       rScale*sTms.tms_stime,
313       rScale*sTms.tms_cutime,
314       rScale*sTms.tms_cstime);
315     fclose(log);
316   }
317 }
318 
is_same_page(const char * zPage1,const char * zPage2)319 static int is_same_page(const char *zPage1, const char *zPage2){
320   size_t s1 = strcspn(zPage1,"?#");
321   size_t s2 = strcspn(zPage2,"?#");
322   if( s1 != s2 ) return 0;
323   return !strncmp(zPage1,zPage2,s1);
324 }
325 
326 /*
327 ** Do a redirect request to the URL given in the argument.
328 **
329 ** The URL might be relative to the current document.  If so,
330 ** this routine has to translate the URL into an absolute
331 ** before formatting the reply.
332 */
cgi_redirect(const char * zURL)333 void cgi_redirect(const char *zURL){
334   char *zLocation;
335   if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 || *zURL=='/' ){
336     /* An absolute URL.  Do nothing */
337   }else{
338     int i, j, k=0;
339     char *zDest;
340     char *zCur = getenv("REQUEST_URI");
341     if( zCur==0 ) zCur = "";
342     for(i=0; zCur[i] && zCur[i]!='?' && zCur[i]!='#'; i++){}
343     if( g.zExtra ){
344       /* Skip to start of extra stuff, then pass over any /'s that might
345       ** have separated the document root from the extra stuff. This
346       ** ensures that the redirection actually redirects the root, not
347       ** something deep down at the bottom of a URL.
348       */
349       i -= strlen(g.zExtra);
350       while( i>0 && zCur[i-1]=='/' ){ i--; }
351     }
352     while( i>0 && zCur[i-1]!='/' ){ i--; }
353     zDest = mprintf("%.*s/%s", i, zCur, zURL);
354     /* don't touch the protocol stuff, if it exists */
355     if( !strncmp(zDest,"http://",7) ){
356       k = 7;
357     }else if( !strncmp(zDest,"https://",8) ){
358       k = 8;
359     }
360     /* strip out constructs like .., /./, //, etc */
361     for(i=j=k; zDest[i]; i++){
362       if( zDest[i]=='/' ){
363         if( zDest[i+1]=='.' ){
364           if( zDest[i+2]=='/' ){
365             i += 2;
366             continue;
367           }
368           if( zDest[i+2]=='.' && zDest[i+3]=='/' ){
369             if( j==0 ){
370               i += 3;
371               continue;
372             }
373             j--;
374             while( j>0 && zDest[j-1]!='/' ){ j--; }
375             continue;
376           }
377         }
378         if( zDest[i+1]=='/' && (i==0 || zDest[i-1]!=':') ) continue;
379       }
380       zDest[j++] = zDest[i];
381     }
382     zDest[j] = 0;
383     zURL = zDest;
384 
385     /* see if we've got a cycle by matching everything up to the ? or #
386     ** in the new and old URLs.
387     */
388     if( is_same_page(zDest,zCur) ){
389       cgi_reset_content();
390       cgi_printf("<html>\n<p>Cyclic redirection in %s</p>\n</html>\n", zURL);
391       cgi_set_status(500, "Internal Server Error");
392       cgi_reply();
393       exit(0);
394     }
395   }
396 
397 /*
398 ** The lynx browser complains if the "http:" prefix is missing
399 ** from a redirect.  But if we use it, we lose the ability to
400 ** run on a secure server using stunnel.
401 **
402 ** Relative redirects are used by default.  This works with stunnel.
403 ** Lynx sends us a nasty message, but it still works.  So with
404 ** relative redirects everybody works.  With absolute redirects,
405 ** stunnel will not work.  So the default configuration is to go
406 ** with what works for everybody, even if it happens to be technically
407 ** incorrect.
408 */
409 #ifdef ABSOLUTE_REDIRECT
410   {
411     char *zHost;
412     if( strncmp(zURL,"http:",5)!=0 && strncmp(zURL,"https:",6)!=0
413          && (zHost = getenv("HTTP_HOST"))!=0 ){
414       char *zMode = getenv("HTTPS");
415       if( zMode && strcmp(zMode,"on")==0 ){
416         zURL = mprintf("https://%s%s", zHost, zURL);
417       }else{
418         zURL = mprintf("http://%s%s", zHost, zURL);
419       }
420     }
421   }
422 #endif
423   zLocation = mprintf("Location: %s\r\n", zURL);
424   cgi_append_header(zLocation);
425   cgi_reset_content();
426   cgi_printf("<html>\n<p>Redirect to %h</p>\n</html>\n", zURL);
427   cgi_set_status(302, "Moved Temporarily");
428   free(zLocation);
429   cgi_reply();
430   exit(0);
431 }
432 
433 /*
434 ** Information about all query parameters and cookies are stored
435 ** in these variables.
436 */
437 static int nAllocQP = 0; /* Space allocated for aParamQP[] */
438 static int nUsedQP = 0;  /* Space actually used in aParamQP[] */
439 static int sortQP = 0;   /* True if aParamQP[] needs sorting */
440 static struct QParam {   /* One entry for each query parameter or cookie */
441   char *zName;              /* Parameter or cookie name */
442   char *zValue;             /* Value of the query parameter or cookie */
443 } *aParamQP;             /* An array of all parameters and cookies */
444 
445 /*
446 ** Add another query parameter or cookie to the parameter set.
447 ** zName is the name of the query parameter or cookie and zValue
448 ** is its fully decoded value.
449 **
450 ** zName and zValue are not copied and must not change or be
451 ** deallocated after this routine returns.
452 */
cgi_set_parameter_nocopy(char * zName,char * zValue)453 static void cgi_set_parameter_nocopy(char *zName, char *zValue){
454   if( nAllocQP<=nUsedQP ){
455     nAllocQP = nAllocQP*2 + 10;
456     aParamQP = realloc( aParamQP, nAllocQP*sizeof(aParamQP[0]) );
457     if( aParamQP==0 ) exit(1);
458   }
459   aParamQP[nUsedQP].zName = zName;
460   aParamQP[nUsedQP].zValue = zValue;
461   nUsedQP++;
462   sortQP = 1;
463 }
464 
465 /*
466 ** Add another query parameter or cookie to the parameter set.
467 ** zName is the name of the query parameter or cookie and zValue
468 ** is its fully decoded value.
469 **
470 ** Copies are made of both the zName and zValue parameters.
471 */
cgi_set_parameter(const char * zName,const char * zValue)472 void cgi_set_parameter(const char *zName, const char *zValue){
473   cgi_set_parameter_nocopy(mprintf("%s",zName), mprintf("%s",zValue));
474 }
475 
476 
477 /*
478 ** Add a list of query parameters or cookies to the parameter set.
479 **
480 ** Each parameter is of the form NAME=VALUE.  Both the NAME and the
481 ** VALUE may be url-encoded ("+" for space, "%HH" for other special
482 ** characters).  But this routine assumes that NAME contains no
483 ** special character and therefore does not decode it.
484 **
485 ** Parameters are separated by the "terminator" character.  Whitespace
486 ** before the NAME is ignored.
487 **
488 ** The input string "z" is modified but no copies is made.  "z"
489 ** should not be deallocated or changed again after this routine
490 ** returns or it will corrupt the parameter table.
491 */
add_param_list(char * z,int terminator)492 static void add_param_list(char *z, int terminator){
493   while( *z ){
494     char *zName;
495     char *zValue;
496     while( isspace(*z) ){ z++; }
497     zName = z;
498     while( *z && *z!='=' && *z!=terminator ){ z++; }
499     if( *z=='=' ){
500       *z = 0;
501       z++;
502       zValue = z;
503       while( *z && *z!=terminator ){ z++; }
504       if( *z ){
505         *z = 0;
506         z++;
507       }
508       dehttpize(zValue);
509       cgi_set_parameter_nocopy(zName, zValue);
510     }else{
511       if( *z ){ *z++ = 0; }
512       cgi_set_parameter_nocopy(zName, "");
513     }
514   }
515 }
516 
517 /*
518 ** *pz is a string that consists of multiple lines of text.  This
519 ** routine finds the end of the current line of text and converts
520 ** the "\n" or "\r\n" that ends that line into a "\000".  It then
521 ** advances *pz to the beginning of the next line and returns the
522 ** previous value of *pz (which is the start of the current line.)
523 */
get_line_from_string(char ** pz,int * pLen)524 static char *get_line_from_string(char **pz, int *pLen){
525   char *z = *pz;
526   int i;
527   if( z[0]==0 ) return 0;
528   for(i=0; z[i]; i++){
529     if( z[i]=='\n' ){
530       if( i>0 && z[i-1]=='\r' ){
531         z[i-1] = 0;
532       }else{
533         z[i] = 0;
534       }
535       i++;
536       break;
537     }
538   }
539   *pz = &z[i];
540   *pLen -= i;
541   return z;
542 }
543 
544 /*
545 ** The input *pz points to content that is terminated by a "\r\n"
546 ** followed by the boundry marker zBoundry.  An extra "--" may or
547 ** may not be appended to the boundry marker.  There are *pLen characters
548 ** in *pz.
549 **
550 ** This routine adds a "\000" to the end of the content (overwriting
551 ** the "\r\n" and returns a pointer to the content.  The *pz input
552 ** is adjusted to point to the first line following the boundry.
553 ** The length of the content is stored in *pnContent.
554 */
get_bounded_content(char ** pz,int * pLen,char * zBoundry,int * pnContent)555 static char *get_bounded_content(
556   char **pz,         /* Content taken from here */
557   int *pLen,         /* Number of bytes of data in (*pz)[] */
558   char *zBoundry,    /* Boundry text marking the end of content */
559   int *pnContent     /* Write the size of the content here */
560 ){
561   char *z = *pz;
562   int len = *pLen;
563   int i;
564   int nBoundry = strlen(zBoundry);
565   *pnContent = len;
566   for(i=0; i<len; i++){
567     if( z[i]=='\n' && strncmp(zBoundry, &z[i+1], nBoundry)==0 ){
568       if( i>0 && z[i-1]=='\r' ) i--;
569       z[i] = 0;
570       *pnContent = i;
571       i += nBoundry;
572       break;
573     }
574   }
575   *pz = &z[i];
576   get_line_from_string(pz, pLen);
577   return z;
578 }
579 
580 /*
581 ** Tokenize a line of text into as many as nArg tokens.  Make
582 ** azArg[] point to the start of each token.
583 **
584 ** Tokens consist of space or semi-colon delimited words or
585 ** strings inside double-quotes.  Example:
586 **
587 **    content-disposition: form-data; name="fn"; filename="index.html"
588 **
589 ** The line above is tokenized as follows:
590 **
591 **    azArg[0] = "content-disposition:"
592 **    azArg[1] = "form-data"
593 **    azArg[2] = "name="
594 **    azArg[3] = "fn"
595 **    azArg[4] = "filename="
596 **    azArg[5] = "index.html"
597 **    azArg[6] = 0;
598 **
599 ** '\000' characters are inserted in z[] at the end of each token.
600 ** This routine returns the total number of tokens on the line, 6
601 ** in the example above.
602 */
tokenize_line(char * z,int mxArg,char ** azArg)603 static int tokenize_line(char *z, int mxArg, char **azArg){
604   int i = 0;
605   while( *z ){
606     while( isspace(*z) || *z==';' ){ z++; }
607     if( *z=='"' && z[1] ){
608       *z = 0;
609       z++;
610       if( i<mxArg-1 ){ azArg[i++] = z; }
611       while( *z && *z!='"' ){ z++; }
612       if( *z==0 ) break;
613       *z = 0;
614       z++;
615     }else{
616       if( i<mxArg-1 ){ azArg[i++] = z; }
617       while( *z && !isspace(*z) && *z!=';' && *z!='"' ){ z++; }
618       if( *z && *z!='"' ){
619         *z = 0;
620         z++;
621       }
622     }
623   }
624   azArg[i] = 0;
625   return i;
626 }
627 
628 /*
629 ** Scan the multipart-form content and make appropriate entries
630 ** into the parameter table.
631 **
632 ** The content string "z" is modified by this routine but it is
633 ** not copied.  The calling function must not deallocate or modify
634 ** "z" after this routine finishes or it could corrupt the parameter
635 ** table.
636 */
process_multipart_form_data(char * z,int len)637 static void process_multipart_form_data(char *z, int len){
638   char *zLine;
639   int nArg, i;
640   char *zBoundry;
641   char *zValue;
642   char *zName = 0;
643   int showBytes = 0;
644   char *azArg[50];
645 
646   zBoundry = get_line_from_string(&z, &len);
647   if( zBoundry==0 ) return;
648   while( (zLine = get_line_from_string(&z, &len))!=0 ){
649     if( zLine[0]==0 ){
650       int nContent = 0;
651       zValue = get_bounded_content(&z, &len, zBoundry, &nContent);
652       if( zName && zValue ){
653         cgi_set_parameter_nocopy(zName, zValue);
654         if( showBytes ){
655           cgi_set_parameter_nocopy(mprintf("%s:bytes", zName),
656                mprintf("%d",nContent));
657         }
658       }
659       zName = 0;
660       showBytes = 0;
661     }else{
662       nArg = tokenize_line(zLine, sizeof(azArg)/sizeof(azArg[0]), azArg);
663       for(i=0; i<nArg; i++){
664         int c = tolower(azArg[i][0]);
665         if( c=='c' && strcasecmp(azArg[i],"content-disposition:")==0 ){
666           i++;
667         }else if( c=='n' && strcasecmp(azArg[i],"name=")==0 ){
668           zName = azArg[++i];
669         }else if( c=='f' && strcasecmp(azArg[i],"filename=")==0 ){
670           char *z = azArg[++i];
671           if( zName && z ){
672             cgi_set_parameter_nocopy(mprintf("%s:filename",zName), z);
673           }
674           showBytes = 1;
675         }else if( c=='c' && strcasecmp(azArg[i],"content-type:")==0 ){
676           char *z = azArg[++i];
677           if( zName && z ){
678             cgi_set_parameter_nocopy(mprintf("%s:mimetype",zName), z);
679           }
680         }
681       }
682     }
683   }
684 }
685 
686 /*
687 ** Initialize the query parameter database.  Information is pulled from
688 ** the QUERY_STRING environment variable (if it exists), from standard
689 ** input if there is POST data, and from HTTP_COOKIE.
690 */
cgi_init(void)691 void cgi_init(void){
692   char *z;
693   char *zType;
694   int len;
695   z = getenv("QUERY_STRING");
696   if( z ){
697     z = mprintf("%s",z);
698     add_param_list(z, '&');
699   }
700 
701   z = getenv("CONTENT_LENGTH");
702   len = z ? atoi(z) : 0;
703   zType = getenv("CONTENT_TYPE");
704   if( len>0 && zType &&
705     (strcmp(zType,"application/x-www-form-urlencoded")==0
706       || strncmp(zType,"multipart/form-data",19)==0) ){
707     z = malloc( len+1 );
708     if( z==0 ) exit(1);
709     len = fread(z, 1, len, stdin);
710     z[len] = 0;
711     if( zType[0]=='a' ){
712       add_param_list(z, '&');
713     }else{
714       process_multipart_form_data(z, len);
715     }
716   }
717 
718   z = getenv("HTTP_COOKIE");
719   if( z ){
720     z = mprintf("%s",z);
721     add_param_list(z, ';');
722   }
723 }
724 
725 /*
726 ** This is the comparison function used to sort the aParamQP[] array of
727 ** query parameters and cookies.
728 */
qparam_compare(const void * a,const void * b)729 static int qparam_compare(const void *a, const void *b){
730   struct QParam *pA = (struct QParam*)a;
731   struct QParam *pB = (struct QParam*)b;
732   return strcmp(pA->zName, pB->zName);
733 }
734 
735 /*
736 ** Return the value of a query parameter or cookie whose name is zName.
737 ** If there is no query parameter or cookie named zName, then return
738 ** zDefault instead.
739 */
cgi_parameter(const char * zName,const char * zDefault)740 const char *cgi_parameter(const char *zName, const char *zDefault){
741   int lo, hi, mid, c;
742   if( nUsedQP<=0 ) return zDefault;
743   if( sortQP ){
744     qsort(aParamQP, nUsedQP, sizeof(aParamQP[0]), qparam_compare);
745     sortQP = 0;
746   }
747   lo = 0;
748   hi = nUsedQP-1;
749   while( lo<=hi ){
750     mid = (lo+hi)/2;
751     c = strcmp(aParamQP[mid].zName, zName);
752     if( c==0 ){
753       return aParamQP[mid].zValue;
754     }else if( c>0 ){
755       hi = mid-1;
756     }else{
757       lo = mid+1;
758     }
759   }
760   return zDefault;
761 }
762 
763 /*
764 ** Return true if any of the query parameters in the argument
765 ** list are defined.
766 */
cgi_any(const char * z,...)767 int cgi_any(const char *z, ...){
768   va_list ap;
769   char *z2;
770   if( cgi_parameter(z,0)!=0 ) return 1;
771   va_start(ap, z);
772   while( (z2 = va_arg(ap, char*))!=0 ){
773     if( cgi_parameter(z2,0)!=0 ) return 1;
774   }
775   va_end(ap);
776   return 0;
777 }
778 
779 /*
780 ** Return true if all of the query parameters in the argument list
781 ** are defined.
782 */
cgi_all(const char * z,...)783 int cgi_all(const char *z, ...){
784   va_list ap;
785   char *z2;
786   if( cgi_parameter(z,0)==0 ) return 0;
787   va_start(ap, z);
788   while( (z2 = va_arg(ap, char*))==0 ){
789     if( cgi_parameter(z2,0)==0 ) return 0;
790   }
791   va_end(ap);
792   return 1;
793 }
794 
795 /*
796 ** Print all query parameters on standard output.  Format the
797 ** parameters as HTML.  This is used for testing and debugging.
798 */
cgi_print_all(void)799 void cgi_print_all(void){
800   int i;
801   cgi_parameter("","");  /* For the parameters into sorted order */
802   for(i=0; i<nUsedQP; i++){
803     cgi_printf("%s = %s  <br />\n",
804        htmlize(aParamQP[i].zName, -1), htmlize(aParamQP[i].zValue, -1));
805   }
806 }
807 
808 /*
809 ** Write HTML text for an option menu to standard output.  zParam
810 ** is the query parameter that the option menu sets.  zDflt is the
811 ** initial value of the option menu.  Additional arguments are name/value
812 ** pairs that define values on the menu.  The list is terminated with
813 ** a single NULL argument.
814 */
cgi_optionmenu(int in,const char * zP,const char * zD,...)815 void cgi_optionmenu(int in, const char *zP, const char *zD, ...){
816   va_list ap;
817   char *zName, *zVal;
818   int dfltSeen = 0;
819   cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
820   va_start(ap, zD);
821   while( (zName = va_arg(ap, char*))!=0 && (zVal = va_arg(ap, char*))!=0 ){
822     if( strcmp(zVal,zD)==0 ){ dfltSeen = 1; break; }
823   }
824   va_end(ap);
825   if( !dfltSeen ){
826     if( zD[0] ){
827       cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
828         in+2, "", zD, zD);
829     }else{
830       cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n", in+2, "");
831     }
832   }
833   va_start(ap, zD);
834   while( (zName = va_arg(ap, char*))!=0 && (zVal = va_arg(ap, char*))!=0 ){
835     if( zName[0] ){
836       cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
837         in+2, "",
838         zVal,
839         strcmp(zVal, zD) ? "" : " selected",
840         zName
841       );
842     }else{
843       cgi_printf("%*s<option value=\"\"%s>&nbsp;</option>\n",
844         in+2, "",
845         strcmp(zVal, zD) ? "" : " selected"
846       );
847     }
848   }
849   va_end(ap);
850   cgi_printf("%*s</select>\n", in, "");
851 }
852 
853 /*
854 ** This routine works a lot like cgi_optionmenu() except that the list of
855 ** values is contained in an array.  Also, the values are just values, not
856 ** name/value pairs as in cgi_optionmenu.
857 */
cgi_v_optionmenu(int in,const char * zP,const char * zD,const char ** az)858 void cgi_v_optionmenu(
859   int in,              /* Indent by this amount */
860   const char *zP,      /* The query parameter name */
861   const char *zD,      /* Default value */
862   const char **az      /* NULL-terminated list of allowed values */
863 ){
864   const char *zVal;
865   int i;
866   cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
867   for(i=0; az[i]; i++){
868     if( strcmp(az[i],zD)==0 ) break;
869   }
870   if( az[i]==0 ){
871     if( zD[0]==0 ){
872       cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n",
873        in+2, "");
874     }else{
875       cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
876        in+2, "", zD, zD);
877     }
878   }
879   while( (zVal = *(az++))!=0  ){
880     if( zVal[0] ){
881       cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
882         in+2, "",
883         zVal,
884         strcmp(zVal, zD) ? "" : " selected",
885         zVal
886       );
887     }else{
888       cgi_printf("%*s<option value=\"\"%s>&nbsp;</option>\n",
889         in+2, "",
890         strcmp(zVal, zD) ? "" : " selected"
891       );
892     }
893   }
894   cgi_printf("%*s</select>\n", in, "");
895 }
896 
897 /*
898 ** This routine works a lot like cgi_v_optionmenu() except that the list
899 ** is a list of pairs.  The first element of each pair is the value used
900 ** internally and the second element is the value displayed to the user.
901 */
cgi_v_optionmenu2(int in,const char * zP,const char * zD,const char ** az)902 void cgi_v_optionmenu2(
903   int in,              /* Indent by this amount */
904   const char *zP,      /* The query parameter name */
905   const char *zD,      /* Default value */
906   const char **az      /* NULL-terminated list of allowed values */
907 ){
908   const char *zVal;
909   int i;
910   cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
911   for(i=0; az[i]; i+=2){
912     if( strcmp(az[i],zD)==0 ) break;
913   }
914   if( az[i]==0 ){
915     if( zD[0]==0 ){
916       cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n",
917        in+2, "");
918     }else{
919       cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
920        in+2, "", zD, zD);
921     }
922   }
923   while( (zVal = *(az++))!=0  ){
924     const char *zName = *(az++);
925     if( zName[0] ){
926       cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
927         in+2, "",
928         zVal,
929         strcmp(zVal, zD) ? "" : " selected",
930         zName
931       );
932     }else{
933       cgi_printf("%*s<option value=\"%h\"%s>&nbsp;</option>\n",
934         in+2, "",
935         zVal,
936         strcmp(zVal, zD) ? "" : " selected"
937       );
938     }
939   }
940   cgi_printf("%*s</select>\n", in, "");
941 }
942 
943 /*
944 ** This routine should never be called directly. Use wrapper functions below.
945 ** Generates HTML input element to be used in forms.
946 ** Parameters are explained below inline. If any param is 0 that
947 ** attribute/feature will not be used. zValue is required, except for text
948 ** fields. zName is also required except for submit, reset and button.
949 */
cgi_input_elem(int nType,const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,int nSize,int nMaxLen,int nLabelOnLeft,const char * zValue,const char * zDflt,const char * zLabel)950 void cgi_input_elem(
951   int nType,              /* 1:submit, 2:reset, 3:button, 4:file, 5:hidden,
952                           ** 6:checkbox, 7:radio, 8:password, 9:text */
953   const char *zName,      /* CGI param name */
954   const char *zId,        /* HTML element id */
955   const char *zClass,     /* CSS class to apply */
956   char nAccessKey,        /* Access key to assign */
957   int nTabIndex,          /* Element's tab index */
958   int nSize,              /* Used only for text fields */
959   int nMaxLen,            /* Used only for text fields */
960   int nLabelOnLeft,       /* If set, put label text left of element */
961   const char *zValue,     /* Element's value */
962   const char *zDflt,      /* If same as zValue, "select" this element */
963   const char *zLabel      /* Label text. No HTML escaping is done on it */
964 ){
965   /* Buttons and hidden fields can't have label
966   */
967   int bHasLabel = ( nType>4 && zLabel && zLabel[0] );
968 
969   assert( nType > 0 );
970   assert( nType <= 9 );
971   if( zValue==0 ) return;
972   if( nType<1 && nType>3 && (!zName || !zName[0]) ) return;
973   if( bHasLabel ){
974     /* Make sure we have some valid id because <label> won't work in IE w/o it
975     */
976     if( !zId || !zId[0] ) zId = mprintf("%s%h", zName, zValue);
977     @ <label for="%h(zId)">\
978     if( nLabelOnLeft>0 ){
979       @ %s(zLabel) \
980     }
981   }
982 
983   @ <input\
984   switch( nType ){
985     case 1: cgi_printf(" type=\"submit\""); break;
986     case 2: cgi_printf(" type=\"reset\""); break;
987     case 3: cgi_printf(" type=\"button\""); break;
988     case 4: cgi_printf(" type=\"file\""); break;
989     case 5: cgi_printf(" type=\"hidden\""); break;
990     case 6: cgi_printf(" type=\"checkbox\""); break;
991     case 7: cgi_printf(" type=\"radio\""); break;
992     case 8: cgi_printf(" type=\"password\""); break;
993     case 9:
994       @  type="text"\
995       if( nSize>0 ){
996         @  size="%d(nSize)"\
997       }
998       if( nMaxLen>0 ){
999         @  maxlength="%d(nMaxLen)"\
1000       }
1001       break;
1002     default: return;
1003   }
1004 
1005   if( zName && zName[0] ){
1006     @  name="%h(zName)"\
1007   }
1008   if( zId && zId[0] ){
1009     @  id="%h(zId)"\
1010   }
1011   if( zClass && zClass[0] ){
1012     @  class="%h(zClass)"\
1013   }
1014   if( isalnum(nAccessKey) ){
1015     @  accesskey="%c(nAccessKey)"\
1016   }
1017   if( nTabIndex>0 ){
1018     @  tabindex="%d(nTabIndex)"\
1019   }
1020   if( zValue && zValue[0] ){
1021     @  value="%h(zValue)"\
1022   }
1023   if( zDflt && zDflt[0] && strcmp(zDflt, zValue)==0 ){
1024     @  checked\
1025   }
1026   @ >\
1027 
1028   if( bHasLabel ){
1029     if( nLabelOnLeft<=0 ){
1030       @  %s(zLabel)\
1031     }
1032     @ </label>
1033   }else{
1034     @
1035   }
1036 }
1037 
cgi_submit(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,const char * zValue)1038 void cgi_submit(
1039   const char *zName,      /* CGI param name */
1040   const char *zId,        /* HTML element id */
1041   const char *zClass,     /* CSS class to apply */
1042   char nAccessKey,        /* Access key to assign */
1043   int nTabIndex,          /* Element's tab index */
1044   const char *zValue      /* Element's value */
1045 ){
1046   cgi_input_elem(
1047     1, zName, zId, zClass, nAccessKey, nTabIndex, 0, 0, 0, zValue, 0, 0
1048   );
1049 }
1050 
cgi_reset(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,const char * zValue)1051 void cgi_reset(
1052   const char *zName,      /* CGI param name */
1053   const char *zId,        /* HTML element id */
1054   const char *zClass,     /* CSS class to apply */
1055   char nAccessKey,        /* Access key to assign */
1056   int nTabIndex,          /* Element's tab index */
1057   const char *zValue      /* Element's value */
1058 ){
1059   cgi_input_elem(
1060     2, zName, zId, zClass, nAccessKey, nTabIndex, 0, 0, 0, zValue, 0, 0
1061   );
1062 }
1063 
cgi_button(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,const char * zValue)1064 void cgi_button(
1065   const char *zName,      /* CGI param name */
1066   const char *zId,        /* HTML element id */
1067   const char *zClass,     /* CSS class to apply */
1068   char nAccessKey,        /* Access key to assign */
1069   int nTabIndex,          /* Element's tab index */
1070   const char *zValue      /* Element's value */
1071 ){
1072   cgi_input_elem(
1073     3, zName, zId, zClass, nAccessKey, nTabIndex, 0, 0, 0, zValue, 0, 0
1074   );
1075 }
1076 
cgi_file(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,const char * zValue)1077 void cgi_file(
1078   const char *zName,      /* CGI param name */
1079   const char *zId,        /* HTML element id */
1080   const char *zClass,     /* CSS class to apply */
1081   char nAccessKey,        /* Access key to assign */
1082   int nTabIndex,          /* Element's tab index */
1083   const char *zValue      /* Element's value */
1084 ){
1085   cgi_input_elem(
1086     4, zName, zId, zClass, nAccessKey, nTabIndex, 0, 0, 0, zValue, 0, 0
1087   );
1088 }
1089 
1090 
cgi_hidden(const char * zName,const char * zId,const char * zValue)1091 void cgi_hidden(
1092   const char *zName,      /* CGI param name */
1093   const char *zId,        /* HTML element id */
1094   const char *zValue      /* Element's value */
1095 ){
1096   cgi_input_elem(5, zName, zId, 0, 0, 0, 0, 0, 0, zValue, 0, 0);
1097 }
1098 
cgi_checkbox(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,int nLabelOnLeft,const char * zValue,const char * zDflt,const char * zLabel)1099 void cgi_checkbox(
1100   const char *zName,      /* CGI param name */
1101   const char *zId,        /* HTML element id */
1102   const char *zClass,     /* CSS class to apply */
1103   char nAccessKey,        /* Access key to assign */
1104   int nTabIndex,          /* Element's tab index */
1105   int nLabelOnLeft,       /* If set, put label text left of element */
1106   const char *zValue,     /* Element's value */
1107   const char *zDflt,      /* If same as zValue, "select" this element */
1108   const char *zLabel      /* Label text. No HTML escaping is done on it */
1109 ){
1110   cgi_input_elem(
1111     6, zName, zId, zClass, nAccessKey, nTabIndex, 0, 0, nLabelOnLeft,
1112     zValue, zDflt, zLabel
1113   );
1114 }
1115 
cgi_radio(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,int nLabelOnLeft,const char * zValue,const char * zDflt,const char * zLabel)1116 void cgi_radio(
1117   const char *zName,      /* CGI param name */
1118   const char *zId,        /* HTML element id */
1119   const char *zClass,     /* CSS class to apply */
1120   char nAccessKey,        /* Access key to assign */
1121   int nTabIndex,          /* Element's tab index */
1122   int nLabelOnLeft,       /* If set, put label text left of element */
1123   const char *zValue,     /* Element's value */
1124   const char *zDflt,      /* If same as zValue, "select" this element */
1125   const char *zLabel      /* Label text. No HTML escaping is done on it */
1126 ){
1127   cgi_input_elem(
1128     7, zName, zId, zClass, nAccessKey, nTabIndex, 0, 0, nLabelOnLeft,
1129     zValue, zDflt, zLabel
1130   );
1131 }
1132 
cgi_password(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,int nSize,int nMaxLen,int nLabelOnLeft,const char * zValue,const char * zLabel)1133 void cgi_password(
1134   const char *zName,      /* CGI param name */
1135   const char *zId,        /* HTML element id */
1136   const char *zClass,     /* CSS class to apply */
1137   char nAccessKey,        /* Access key to assign */
1138   int nTabIndex,          /* Element's tab index */
1139   int nSize,              /* Field size */
1140   int nMaxLen,            /* Maximum number of chars field will accept */
1141   int nLabelOnLeft,       /* If set, put label text left of element */
1142   const char *zValue,     /* Element's value */
1143   const char *zLabel      /* Label text. No HTML escaping is done on it */
1144 ){
1145   cgi_input_elem(
1146     8, zName, zId, zClass, nAccessKey, nTabIndex, nSize, nMaxLen,
1147     nLabelOnLeft, zValue, 0, zLabel
1148   );
1149 }
1150 
cgi_text(const char * zName,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,int nSize,int nMaxLen,int nLabelOnLeft,const char * zValue,const char * zLabel)1151 void cgi_text(
1152   const char *zName,      /* CGI param name */
1153   const char *zId,        /* HTML element id */
1154   const char *zClass,     /* CSS class to apply */
1155   char nAccessKey,        /* Access key to assign */
1156   int nTabIndex,          /* Element's tab index */
1157   int nSize,              /* Field size */
1158   int nMaxLen,            /* Maximum number of chars field will accept */
1159   int nLabelOnLeft,       /* If set, put label text left of element */
1160   const char *zValue,     /* Element's value */
1161   const char *zLabel      /* Label text. No HTML escaping is done on it */
1162 ){
1163   cgi_input_elem(
1164     9, zName, zId, zClass, nAccessKey, nTabIndex, nSize, nMaxLen,
1165     nLabelOnLeft, zValue, 0, zLabel
1166   );
1167 }
1168 
1169 /*
1170 ** Generates radio button elements grouped in <fieldset>.
1171 ** Parameters are explained below inline. If any param is 0 that
1172 ** attribute/feature will not be used. zName and at least one
1173 ** accesskey/value/label trio are required.
1174 */
cgi_radio_fieldset(const char * zTitle,const char * zName,const char * zClass,int * nTabIndex,const char * zDflt,...)1175 void cgi_radio_fieldset(
1176   const char *zTitle,     /* Title of <fieldset>. If 0 <fieldset> is not used */
1177   const char *zName,      /* CGI param name */
1178   const char *zClass,     /* CSS class to apply to fieldset */
1179   int *nTabIndex,         /* This will be incremented for each element.
1180                           ** Calling func should be able to continue with it */
1181   const char *zDflt,      /* Element with this value will be checked */
1182   ...                     /* NULL-terminated list of value/accesskey/label trios */
1183 ){
1184   char *zVal, *zLabel;
1185   char nAccessKey;
1186   va_list ap;
1187   if( !zName || !zName[0] ) return;
1188 
1189   if( zTitle && zTitle[0] ){
1190     @ <fieldset\
1191     if( zClass && zClass[0] ){
1192       @  class="%h(zClass)"\
1193     }
1194     @ ><legend>%s(zTitle)</legend>
1195   }
1196 
1197   /*
1198   ** args are: accesskey, value, label
1199   */
1200   va_start(ap, zDflt);
1201   while( (zVal = va_arg(ap, char*))!=0 ){
1202     nAccessKey = va_arg(ap, int);
1203     zLabel = va_arg(ap, char*);
1204     if( zLabel==0 ) break;
1205 
1206     cgi_radio(zName, 0, 0, isprint(nAccessKey)? nAccessKey : 0,
1207               nTabIndex==0 ? 0 : ++(*nTabIndex), 0,
1208               zVal, zDflt, zLabel);
1209   }
1210   va_end(ap);
1211   if( nTabIndex ) (*nTabIndex)++;
1212   if( zTitle && zTitle[0] ){
1213     @ </fieldset>
1214   }
1215 }
1216 
1217 /*
1218 ** Generates checkbox elements grouped in <fieldset>.
1219 ** Parameters are explained below inline. If any param is 0 that
1220 ** attribute/feature will not be used. At least one quintet of
1221 ** name/accesskey/value/default value/label is required.
1222 ** If value and default value are equal, element will be "checked".
1223 */
cgi_checkbox_fieldset(const char * zTitle,const char * zClass,int * nTabIndex,...)1224 void cgi_checkbox_fieldset(
1225   const char *zTitle,     /* Title of <fieldset> */
1226   const char *zClass,     /* CSS class to apply to fieldset */
1227   int *nTabIndex,         /* This will be incremented for each element.
1228                           ** Calling func should be able to continue with it */
1229   ...                     /* NULL-terminated list of
1230                           ** name/value/accesskey/label trios */
1231 ){
1232   va_list ap;
1233   int nAccessKey;
1234   char *zName, *zVal, *zDflt, *zLabel;
1235 
1236   if( zTitle && zTitle[0] ){
1237     @ <fieldset\
1238     if( zClass && zClass[0] ){
1239       @  class="%h(zClass)"\
1240     }
1241     @ ><legend>%s(zTitle)</legend>
1242   }
1243   va_start(ap, nTabIndex);
1244   while( (zName = va_arg(ap, char*))!=0 ){
1245     zVal = va_arg(ap, char*);
1246     nAccessKey = va_arg(ap, int);
1247     zDflt = va_arg(ap, char*);
1248     zLabel = va_arg(ap, char*);
1249     if( !zName || !zName[0] || !zVal || !zVal[0] || !zLabel || !zLabel[0] ){
1250       break;
1251     }
1252     /* Label won't work without id in IE so we dummy up id here.
1253     ** Hopefully this won't clash with anyones's CSS.
1254     */
1255     cgi_checkbox(zName, 0, 0, nAccessKey, nTabIndex==0 ? 0 : ++(*nTabIndex), 0,
1256               zVal, zDflt, zLabel);
1257   }
1258   va_end(ap);
1259   if( nTabIndex ) (*nTabIndex)++;
1260   if( zTitle && zTitle[0] ){
1261     @ </fieldset>
1262   }
1263 }
1264 
1265 /*
1266 ** Generates HTML links (<a> element).
1267 ** Parameters are explained below inline. If any param is 0 that
1268 ** attribute/feature will not be used. zText and zHref are required.
1269 */
cgi_href(const char * zText,const char * zId,const char * zClass,char nAccessKey,int nTabIndex,const char * zTitle,const char * zHref,...)1270 void cgi_href(
1271   const char *zText,      /* Link text */
1272   const char *zId,        /* HTML element id */
1273   const char *zClass,     /* CSS class to apply */
1274   char nAccessKey,        /* Access key to assign */
1275   int nTabIndex,          /* Element's tab index */
1276   const char *zTitle,     /* Title to apply to <a> */
1277   const char *zHref,      /* Link address (vxprintf() format) */
1278   ...
1279 ){
1280   va_list ap;
1281 
1282   if( !zText || !zText[0] || !zHref || !zHref[0] ) return;
1283 
1284   @ <a href="\
1285   va_start(ap, zHref);
1286   cgi_vprintf(zHref, ap);
1287   va_end(ap);
1288   @ "\
1289 
1290   if( zId && zId[0] ){
1291     @  id="%h(zId)"\
1292   }
1293   if( zClass && zClass[0] ){
1294     @  class="%h(zClass)"\
1295   }
1296   if( isalnum(nAccessKey) ){
1297     @  accesskey="%c(nAccessKey)"\
1298   }
1299   if( nTabIndex>0 ){
1300     @  tabindex="%d(nTabIndex)"\
1301   }
1302   if( zTitle && zTitle[0] ){
1303     @  title="%h(zTitle)"\
1304   }
1305 
1306   @ >%h(zText)</a>
1307 }
1308 
1309 /*
1310 ** The "printf" code that follows dates from the 1980's.  It is in
1311 ** the public domain.  The original comments are included here for
1312 ** completeness.  They are slightly out-of-date.
1313 **
1314 ** The following modules is an enhanced replacement for the "printf" programs
1315 ** found in the standard library.  The following enhancements are
1316 ** supported:
1317 **
1318 **      +  Additional functions.  The standard set of "printf" functions
1319 **         includes printf, fprintf, sprintf, vprintf, vfprintf, and
1320 **         vsprintf.  This module adds the following:
1321 **
1322 **           *  snprintf -- Works like sprintf, but has an extra argument
1323 **                          which is the size of the buffer written to.
1324 **
1325 **           *  mprintf --  Similar to sprintf.  Writes output to memory
1326 **                          obtained from malloc.
1327 **
1328 **           *  xprintf --  Calls a function to dispose of output.
1329 **
1330 **           *  nprintf --  No output, but returns the number of characters
1331 **                          that would have been output by printf.
1332 **
1333 **           *  A v- version (ex: vsnprintf) of every function is also
1334 **              supplied.
1335 **
1336 **      +  A few extensions to the formatting notation are supported:
1337 **
1338 **           *  The "=" flag (similar to "-") causes the output to be
1339 **              be centered in the appropriately sized field.
1340 **
1341 **           *  The %b field outputs an integer in binary notation.
1342 **
1343 **           *  The %c field now accepts a precision.  The character output
1344 **              is repeated by the number of times the precision specifies.
1345 **
1346 **           *  The %' field works like %c, but takes as its character the
1347 **              next character of the format string, instead of the next
1348 **              argument.  For example,  printf("%.78'-")  prints 78 minus
1349 **              signs, the same as  printf("%.78c",'-').
1350 **
1351 **      +  When compiled using GCC on a SPARC, this version of printf is
1352 **         faster than the library printf for SUN OS 4.1.
1353 **
1354 **      +  All functions are fully reentrant.
1355 **
1356 */
1357 
1358 /*
1359 ** Undefine COMPATIBILITY to make some slight changes in the way things
1360 ** work.  I think the changes are an improvement, but they are not
1361 ** backwards compatible.
1362 */
1363 /* #define COMPATIBILITY       / * Compatible with SUN OS 4.1 */
1364 
1365 /*
1366 ** Conversion types fall into various categories as defined by the
1367 ** following enumeration.
1368 */
1369 enum et_type {    /* The type of the format field */
1370    etRADIX,            /* Integer types.  %d, %x, %o, and so forth */
1371    etFLOAT,            /* Floating point.  %f */
1372    etEXP,              /* Exponentional notation. %e and %E */
1373    etGENERIC,          /* Floating or exponential, depending on exponent. %g */
1374    etSIZE,             /* Return number of characters processed so far. %n */
1375    etSTRING,           /* Strings. %s */
1376    etPERCENT,          /* Percent symbol. %% */
1377    etCHARX,            /* Characters. %c */
1378    etERROR,            /* Used to indicate no such conversion type */
1379 /* The rest are extensions, not normally found in printf() */
1380    etCHARLIT,          /* Literal characters.  %' */
1381    etDYNAMIC,          /* Like %s but free() called on input */
1382    etORDINAL,          /* 1st, 2nd, 3rd and so forth */
1383    etHTMLIZE,          /* Make text safe for HTML */
1384    etHTTPIZE,          /* Make text safe for HTTP.  "/" encoded as %2f */
1385    etURLIZE            /* Make text safe for HTTP.  "/" not encoded */
1386 };
1387 
1388 /*
1389 ** Each builtin conversion character (ex: the 'd' in "%d") is described
1390 ** by an instance of the following structure
1391 */
1392 typedef struct et_info {   /* Information about each format field */
1393   int  fmttype;              /* The format field code letter */
1394   int  base;                 /* The base for radix conversion */
1395   char *charset;             /* The character set for conversion */
1396   int  flag_signed;          /* Is the quantity signed? */
1397   char *prefix;              /* Prefix on non-zero values in alt format */
1398   enum et_type type;          /* Conversion paradigm */
1399 } et_info;
1400 
1401 /*
1402 ** The following table is searched linearly, so it is good to put the
1403 ** most frequently used conversion types first.
1404 */
1405 static et_info fmtinfo[] = {
1406   { 'd',  10,  "0123456789",       1,    0, etRADIX,      },
1407   { 's',   0,  0,                  0,    0, etSTRING,     },
1408   { 'z',   0,  0,                  0,    0, etDYNAMIC,    },
1409   { 'h',   0,  0,                  0,    0, etHTMLIZE,    },
1410   { 't',   0,  0,                  0,    0, etHTTPIZE,    }, /* / -> %2F */
1411   { 'T',   0,  0,                  0,    0, etURLIZE,     }, /* / -> / */
1412   { 'c',   0,  0,                  0,    0, etCHARX,      },
1413   { 'o',   8,  "01234567",         0,  "0", etRADIX,      },
1414   { 'u',  10,  "0123456789",       0,    0, etRADIX,      },
1415   { 'x',  16,  "0123456789abcdef", 0, "x0", etRADIX,      },
1416   { 'X',  16,  "0123456789ABCDEF", 0, "X0", etRADIX,      },
1417   { 'r',  10,  "0123456789",       0,    0, etORDINAL,    },
1418   { 'f',   0,  0,                  1,    0, etFLOAT,      },
1419   { 'e',   0,  "e",                1,    0, etEXP,        },
1420   { 'E',   0,  "E",                1,    0, etEXP,        },
1421   { 'g',   0,  "e",                1,    0, etGENERIC,    },
1422   { 'G',   0,  "E",                1,    0, etGENERIC,    },
1423   { 'i',  10,  "0123456789",       1,    0, etRADIX,      },
1424   { 'n',   0,  0,                  0,    0, etSIZE,       },
1425   { '%',   0,  0,                  0,    0, etPERCENT,    },
1426   { 'b',   2,  "01",               0, "b0", etRADIX,      }, /* Binary */
1427   { 'p',  10,  "0123456789",       0,    0, etRADIX,      }, /* Pointers */
1428   { '\'',  0,  0,                  0,    0, etCHARLIT,    }, /* Literal char */
1429 };
1430 #define etNINFO  (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
1431 
1432 /*
1433 ** If NOFLOATINGPOINT is defined, then none of the floating point
1434 ** conversions will work.
1435 */
1436 #ifndef etNOFLOATINGPOINT
1437 /*
1438 ** "*val" is a double such that 0.1 <= *val < 10.0
1439 ** Return the ascii code for the leading digit of *val, then
1440 ** multiply "*val" by 10.0 to renormalize.
1441 **
1442 ** Example:
1443 **     input:     *val = 3.14159
1444 **     output:    *val = 1.4159    function return = '3'
1445 **
1446 ** The counter *cnt is incremented each time.  After counter exceeds
1447 ** 16 (the number of significant digits in a 64-bit float) '0' is
1448 ** always returned.
1449 */
et_getdigit(double * val,int * cnt)1450 static int et_getdigit(double *val, int *cnt){
1451   int digit;
1452   double d;
1453   if( (*cnt)++ >= 16 ) return '0';
1454   digit = (int)*val;
1455   d = digit;
1456   digit += '0';
1457   *val = (*val - d)*10.0;
1458   return digit;
1459 }
1460 #endif
1461 
1462 #define etBUFSIZE 1000  /* Size of the output buffer */
1463 
1464 /*
1465 ** The root program.  All variations call this core.
1466 **
1467 ** INPUTS:
1468 **   func   This is a pointer to a function taking three arguments
1469 **            1. A pointer to anything.  Same as the "arg" parameter.
1470 **            2. A pointer to the list of characters to be output
1471 **               (Note, this list is NOT null terminated.)
1472 **            3. An integer number of characters to be output.
1473 **               (Note: This number might be zero.)
1474 **
1475 **   arg    This is the pointer to anything which will be passed as the
1476 **          first argument to "func".  Use it for whatever you like.
1477 **
1478 **   fmt    This is the format string, as in the usual print.
1479 **
1480 **   ap     This is a pointer to a list of arguments.  Same as in
1481 **          vfprint.
1482 **
1483 ** OUTPUTS:
1484 **          The return value is the total number of characters sent to
1485 **          the function "func".  Returns -1 on a error.
1486 **
1487 ** Note that the order in which automatic variables are declared below
1488 ** seems to make a big difference in determining how fast this beast
1489 ** will run.
1490 */
vxprintf(void (* func)(void *,char *,int),void * arg,const char * format,va_list ap)1491 static int vxprintf(
1492   void (*func)(void*,char*,int),
1493   void *arg,
1494   const char *format,
1495   va_list ap
1496 ){
1497   register const char *fmt; /* The format string. */
1498   register int c;           /* Next character in the format string */
1499   register char *bufpt;     /* Pointer to the conversion buffer */
1500   register int  precision;  /* Precision of the current field */
1501   register int  length;     /* Length of the field */
1502   register int  idx;        /* A general purpose loop counter */
1503   int count;                /* Total number of characters output */
1504   int width;                /* Width of the current field */
1505   int flag_leftjustify;     /* True if "-" flag is present */
1506   int flag_plussign;        /* True if "+" flag is present */
1507   int flag_blanksign;       /* True if " " flag is present */
1508   int flag_alternateform;   /* True if "#" flag is present */
1509   int flag_zeropad;         /* True if field width constant starts with zero */
1510   int flag_long;            /* True if "l" flag is present */
1511   int flag_center;          /* True if "=" flag is present */
1512   unsigned long longvalue;  /* Value for integer types */
1513   double realvalue;         /* Value for real types */
1514   et_info *infop;           /* Pointer to the appropriate info structure */
1515   char buf[etBUFSIZE];      /* Conversion buffer */
1516   char prefix;              /* Prefix character.  "+" or "-" or " " or '\0'. */
1517   int  errorflag = 0;       /* True if an error is encountered */
1518   enum et_type xtype;       /* Conversion paradigm */
1519   char *zMem;               /* String to be freed */
1520   char *zExtra;             /* Extra memory to be freed after use */
1521   static char spaces[] = "                                                  "
1522      "                                                                      ";
1523 #define etSPACESIZE (sizeof(spaces)-1)
1524 #ifndef etNOFLOATINGPOINT
1525   int  exp;                 /* exponent of real numbers */
1526   double rounder;           /* Used for rounding floating point values */
1527   int flag_dp;              /* True if decimal point should be shown */
1528   int flag_rtz;             /* True if trailing zeros should be removed */
1529   int flag_exp;             /* True to force display of the exponent */
1530   int nsd;                  /* Number of significant digits returned */
1531 #endif
1532 
1533   fmt = format;                     /* Put in a register for speed */
1534   count = length = 0;
1535   bufpt = 0;
1536   for(; (c=(*fmt))!=0; ++fmt){
1537     if( c!='%' ){
1538       register int amt;
1539       bufpt = (char *)fmt;
1540       amt = 1;
1541       while( (c=(*++fmt))!='%' && c!=0 ) amt++;
1542       (*func)(arg,bufpt,amt);
1543       count += amt;
1544       if( c==0 ) break;
1545     }
1546     if( (c=(*++fmt))==0 ){
1547       errorflag = 1;
1548       (*func)(arg,"%",1);
1549       count++;
1550       break;
1551     }
1552     /* Find out what flags are present */
1553     flag_leftjustify = flag_plussign = flag_blanksign =
1554      flag_alternateform = flag_zeropad = flag_center = 0;
1555     do{
1556       switch( c ){
1557         case '-':   flag_leftjustify = 1;     c = 0;   break;
1558         case '+':   flag_plussign = 1;        c = 0;   break;
1559         case ' ':   flag_blanksign = 1;       c = 0;   break;
1560         case '#':   flag_alternateform = 1;   c = 0;   break;
1561         case '0':   flag_zeropad = 1;         c = 0;   break;
1562         case '=':   flag_center = 1;          c = 0;   break;
1563         default:                                       break;
1564       }
1565     }while( c==0 && (c=(*++fmt))!=0 );
1566     if( flag_center ) flag_leftjustify = 0;
1567     /* Get the field width */
1568     width = 0;
1569     if( c=='*' ){
1570       width = va_arg(ap,int);
1571       if( width<0 ){
1572         flag_leftjustify = 1;
1573         width = -width;
1574       }
1575       c = *++fmt;
1576     }else{
1577       while( c>='0' && c<='9' ){
1578         width = width*10 + c - '0';
1579         c = *++fmt;
1580       }
1581     }
1582     if( width > etBUFSIZE-10 ){
1583       width = etBUFSIZE-10;
1584     }
1585     /* Get the precision */
1586     if( c=='.' ){
1587       precision = 0;
1588       c = *++fmt;
1589       if( c=='*' ){
1590         precision = va_arg(ap,int);
1591 #ifndef etCOMPATIBILITY
1592         /* This is sensible, but SUN OS 4.1 doesn't do it. */
1593         if( precision<0 ) precision = 0x7fffffff & -precision;
1594 #endif
1595         c = *++fmt;
1596       }else{
1597         while( c>='0' && c<='9' ){
1598           precision = precision*10 + c - '0';
1599           c = *++fmt;
1600         }
1601       }
1602       /* Limit the precision to prevent overflowing buf[] during conversion */
1603       /* if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40; */
1604     }else{
1605       precision = -1;
1606     }
1607     /* Get the conversion type modifier */
1608     if( c=='l' ){
1609       flag_long = 1;
1610       c = *++fmt;
1611     }else{
1612       flag_long = 0;
1613     }
1614     /* Fetch the info entry for the field */
1615     infop = 0;
1616     for(idx=0; idx<etNINFO; idx++){
1617       if( c==fmtinfo[idx].fmttype ){
1618         infop = &fmtinfo[idx];
1619         break;
1620       }
1621     }
1622     /* No info entry found.  It must be an error. */
1623     if( infop==0 ){
1624       xtype = etERROR;
1625     }else{
1626       xtype = infop->type;
1627     }
1628     zExtra = 0;
1629 
1630     /*
1631     ** At this point, variables are initialized as follows:
1632     **
1633     **   flag_alternateform          TRUE if a '#' is present.
1634     **   flag_plussign               TRUE if a '+' is present.
1635     **   flag_leftjustify            TRUE if a '-' is present or if the
1636     **                               field width was negative.
1637     **   flag_zeropad                TRUE if the width began with 0.
1638     **   flag_long                   TRUE if the letter 'l' (ell) prefixed
1639     **                               the conversion character.
1640     **   flag_blanksign              TRUE if a ' ' is present.
1641     **   width                       The specified field width.  This is
1642     **                               always non-negative.  Zero is the default.
1643     **   precision                   The specified precision.  The default
1644     **                               is -1.
1645     **   xtype                       The class of the conversion.
1646     **   infop                       Pointer to the appropriate info struct.
1647     */
1648     switch( xtype ){
1649       case etORDINAL:
1650       case etRADIX:
1651         if( flag_long )  longvalue = va_arg(ap,long);
1652 	else             longvalue = va_arg(ap,int);
1653 #ifdef etCOMPATIBILITY
1654         /* For the format %#x, the value zero is printed "0" not "0x0".
1655         ** I think this is stupid. */
1656         if( longvalue==0 ) flag_alternateform = 0;
1657 #else
1658         /* More sensible: turn off the prefix for octal (to prevent "00"),
1659         ** but leave the prefix for hex. */
1660         if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
1661 #endif
1662         if( infop->flag_signed ){
1663           if( *(long*)&longvalue<0 ){
1664             longvalue = -*(long*)&longvalue;
1665             prefix = '-';
1666           }else if( flag_plussign )  prefix = '+';
1667           else if( flag_blanksign )  prefix = ' ';
1668           else                       prefix = 0;
1669         }else                        prefix = 0;
1670         if( flag_zeropad && precision<width-(prefix!=0) ){
1671           precision = width-(prefix!=0);
1672 	}
1673         bufpt = &buf[etBUFSIZE];
1674         if( xtype==etORDINAL ){
1675           long a,b;
1676           a = longvalue%10;
1677           b = longvalue%100;
1678           bufpt -= 2;
1679           if( a==0 || a>3 || (b>10 && b<14) ){
1680             bufpt[0] = 't';
1681             bufpt[1] = 'h';
1682           }else if( a==1 ){
1683             bufpt[0] = 's';
1684             bufpt[1] = 't';
1685           }else if( a==2 ){
1686             bufpt[0] = 'n';
1687             bufpt[1] = 'd';
1688           }else if( a==3 ){
1689             bufpt[0] = 'r';
1690             bufpt[1] = 'd';
1691           }
1692         }
1693         {
1694           register char *cset;      /* Use registers for speed */
1695           register int base;
1696           cset = infop->charset;
1697           base = infop->base;
1698           do{                                           /* Convert to ascii */
1699             *(--bufpt) = cset[longvalue%base];
1700             longvalue = longvalue/base;
1701           }while( longvalue>0 );
1702 	}
1703         length = (long)&buf[etBUFSIZE]-(long)bufpt;
1704         if( precision>etBUFSIZE-40 ) precision = etBUFSIZE - 40;
1705         for(idx=precision-length; idx>0; idx--){
1706           *(--bufpt) = '0';                             /* Zero pad */
1707 	}
1708         if( prefix ) *(--bufpt) = prefix;               /* Add sign */
1709         if( flag_alternateform && infop->prefix ){      /* Add "0" or "0x" */
1710           char *pre, x;
1711           pre = infop->prefix;
1712           if( *bufpt!=pre[0] ){
1713             for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
1714 	  }
1715         }
1716         length = (long)&buf[etBUFSIZE]-(long)bufpt;
1717         break;
1718       case etFLOAT:
1719       case etEXP:
1720       case etGENERIC:
1721         realvalue = va_arg(ap,double);
1722 #ifndef etNOFLOATINGPOINT
1723         if( precision<0 ) precision = 6;         /* Set default precision */
1724         if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;
1725         if( realvalue<0.0 ){
1726           realvalue = -realvalue;
1727           prefix = '-';
1728 	}else{
1729           if( flag_plussign )          prefix = '+';
1730           else if( flag_blanksign )    prefix = ' ';
1731           else                         prefix = 0;
1732 	}
1733         if( infop->type==etGENERIC && precision>0 ) precision--;
1734         rounder = 0.0;
1735 #ifdef COMPATIBILITY
1736         /* Rounding works like BSD when the constant 0.4999 is used.  Wierd! */
1737         for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
1738 #else
1739         /* It makes more sense to use 0.5 */
1740         for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
1741 #endif
1742         if( infop->type==etFLOAT ) realvalue += rounder;
1743         /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
1744         exp = 0;
1745         if( realvalue>0.0 ){
1746           int k = 0;
1747           while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }
1748           while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }
1749           while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }
1750           while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }
1751           if( k>=100 ){
1752             bufpt = "NaN";
1753             length = 3;
1754             break;
1755           }
1756 	}
1757         bufpt = buf;
1758         /*
1759         ** If the field type is etGENERIC, then convert to either etEXP
1760         ** or etFLOAT, as appropriate.
1761         */
1762         flag_exp = xtype==etEXP;
1763         if( xtype!=etFLOAT ){
1764           realvalue += rounder;
1765           if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
1766         }
1767         if( xtype==etGENERIC ){
1768           flag_rtz = !flag_alternateform;
1769           if( exp<-4 || exp>precision ){
1770             xtype = etEXP;
1771           }else{
1772             precision = precision - exp;
1773             xtype = etFLOAT;
1774           }
1775 	}else{
1776           flag_rtz = 0;
1777 	}
1778         /*
1779         ** The "exp+precision" test causes output to be of type etEXP if
1780         ** the precision is too large to fit in buf[].
1781         */
1782         nsd = 0;
1783         if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){
1784           flag_dp = (precision>0 || flag_alternateform);
1785           if( prefix ) *(bufpt++) = prefix;         /* Sign */
1786           if( exp<0 )  *(bufpt++) = '0';            /* Digits before "." */
1787           else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);
1788           if( flag_dp ) *(bufpt++) = '.';           /* The decimal point */
1789           for(exp++; exp<0 && precision>0; precision--, exp++){
1790             *(bufpt++) = '0';
1791           }
1792           while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
1793           *(bufpt--) = 0;                           /* Null terminate */
1794           if( flag_rtz && flag_dp ){     /* Remove trailing zeros and "." */
1795             while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
1796             if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
1797           }
1798           bufpt++;                            /* point to next free slot */
1799 	}else{    /* etEXP or etGENERIC */
1800           flag_dp = (precision>0 || flag_alternateform);
1801           if( prefix ) *(bufpt++) = prefix;   /* Sign */
1802           *(bufpt++) = et_getdigit(&realvalue,&nsd);  /* First digit */
1803           if( flag_dp ) *(bufpt++) = '.';     /* Decimal point */
1804           while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);
1805           bufpt--;                            /* point to last digit */
1806           if( flag_rtz && flag_dp ){          /* Remove tail zeros */
1807             while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;
1808             if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;
1809           }
1810           bufpt++;                            /* point to next free slot */
1811           if( exp || flag_exp ){
1812             *(bufpt++) = infop->charset[0];
1813             if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */
1814             else       { *(bufpt++) = '+'; }
1815             if( exp>=100 ){
1816               *(bufpt++) = (exp/100)+'0';                /* 100's digit */
1817               exp %= 100;
1818   	    }
1819             *(bufpt++) = exp/10+'0';                     /* 10's digit */
1820             *(bufpt++) = exp%10+'0';                     /* 1's digit */
1821           }
1822 	}
1823         /* The converted number is in buf[] and zero terminated. Output it.
1824         ** Note that the number is in the usual order, not reversed as with
1825         ** integer conversions. */
1826         length = (long)bufpt-(long)buf;
1827         bufpt = buf;
1828 
1829         /* Special case:  Add leading zeros if the flag_zeropad flag is
1830         ** set and we are not left justified */
1831         if( flag_zeropad && !flag_leftjustify && length < width){
1832           int i;
1833           int nPad = width - length;
1834           for(i=width; i>=nPad; i--){
1835             bufpt[i] = bufpt[i-nPad];
1836           }
1837           i = prefix!=0;
1838           while( nPad-- ) bufpt[i++] = '0';
1839           length = width;
1840         }
1841 #endif
1842         break;
1843       case etSIZE:
1844         *(va_arg(ap,int*)) = count;
1845         length = width = 0;
1846         break;
1847       case etPERCENT:
1848         buf[0] = '%';
1849         bufpt = buf;
1850         length = 1;
1851         break;
1852       case etCHARLIT:
1853       case etCHARX:
1854         c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
1855         if( precision>=0 ){
1856           if( precision>etBUFSIZE-1 ) precision = etBUFSIZE-1;
1857           for(idx=1; idx<precision; idx++) buf[idx] = c;
1858           length = precision;
1859 	}else{
1860           length =1;
1861 	}
1862         bufpt = buf;
1863         break;
1864       case etSTRING:
1865         zMem = bufpt = va_arg(ap,char*);
1866         if( bufpt==0 ) bufpt = "";
1867         length = strlen(bufpt);
1868         if( precision>=0 && precision<length ) length = precision;
1869         break;
1870       case etDYNAMIC:
1871         zExtra = zMem = bufpt = va_arg(ap,char*);
1872         if( bufpt==0 ) bufpt = "";
1873         length = strlen(bufpt);
1874         if( precision>=0 && precision<length ) length = precision;
1875         break;
1876       case etHTMLIZE:
1877         zMem = va_arg(ap,char*);
1878         if( zMem==0 ) zMem = "";
1879         zExtra = bufpt = htmlize(zMem, -1);
1880         length = strlen(bufpt);
1881         if( precision>=0 && precision<length ) length = precision;
1882         break;
1883       case etHTTPIZE:
1884         zMem = va_arg(ap,char*);
1885         if( zMem==0 ) zMem = "";
1886         zExtra = bufpt = httpize(zMem, -1);
1887         length = strlen(bufpt);
1888         if( precision>=0 && precision<length ) length = precision;
1889         break;
1890       case etURLIZE:
1891         zMem = va_arg(ap,char*);
1892         if( zMem==0 ) zMem = "";
1893         zExtra = bufpt = urlize(zMem, -1);
1894         length = strlen(bufpt);
1895         if( precision>=0 && precision<length ) length = precision;
1896         break;
1897       case etERROR:
1898         buf[0] = '%';
1899         buf[1] = c;
1900         errorflag = 0;
1901         idx = 1+(c!=0);
1902         (*func)(arg,"%",idx);
1903         count += idx;
1904         if( c==0 ) fmt--;
1905         break;
1906     }/* End switch over the format type */
1907     /*
1908     ** The text of the conversion is pointed to by "bufpt" and is
1909     ** "length" characters long.  The field width is "width".  Do
1910     ** the output.
1911     */
1912     if( !flag_leftjustify ){
1913       register int nspace;
1914       nspace = width-length;
1915       if( nspace>0 ){
1916         if( flag_center ){
1917           nspace = nspace/2;
1918           width -= nspace;
1919           flag_leftjustify = 1;
1920 	}
1921         count += nspace;
1922         while( nspace>=etSPACESIZE ){
1923           (*func)(arg,spaces,etSPACESIZE);
1924           nspace -= etSPACESIZE;
1925         }
1926         if( nspace>0 ) (*func)(arg,spaces,nspace);
1927       }
1928     }
1929     if( length>0 ){
1930       (*func)(arg,bufpt,length);
1931       count += length;
1932     }
1933     if( flag_leftjustify ){
1934       register int nspace;
1935       nspace = width-length;
1936       if( nspace>0 ){
1937         count += nspace;
1938         while( nspace>=etSPACESIZE ){
1939           (*func)(arg,spaces,etSPACESIZE);
1940           nspace -= etSPACESIZE;
1941         }
1942         if( nspace>0 ) (*func)(arg,spaces,nspace);
1943       }
1944     }
1945     if( zExtra ){
1946       free(zExtra);
1947     }
1948   }/* End for loop over the format string */
1949   return errorflag ? -1 : count;
1950 } /* End of function */
1951 
1952 
1953 /* This structure is used to store state information about the
1954 ** write to memory that is currently in progress.
1955 */
1956 struct sgMprintf {
1957   char *zBase;     /* A base allocation */
1958   char *zText;     /* The string collected so far */
1959   int  nChar;      /* Length of the string so far */
1960   int  nAlloc;     /* Amount of space allocated in zText */
1961 };
1962 
1963 /*
1964 ** This function implements the callback from vxprintf.
1965 **
1966 ** This routine add nNewChar characters of text in zNewText to
1967 ** the sgMprintf structure pointed to by "arg".
1968 */
mout(void * arg,char * zNewText,int nNewChar)1969 static void mout(void *arg, char *zNewText, int nNewChar){
1970   struct sgMprintf *pM = (struct sgMprintf*)arg;
1971   if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
1972     pM->nAlloc = pM->nChar + nNewChar*2 + 1;
1973     if( pM->zText==pM->zBase ){
1974       pM->zText = malloc(pM->nAlloc);
1975       if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);
1976     }else{
1977       char *z = realloc(pM->zText, pM->nAlloc);
1978       if( z==0 ){
1979         free(pM->zText);
1980         pM->nChar = 0;
1981         pM->nAlloc = 0;
1982       }
1983       pM->zText = z;
1984     }
1985   }
1986   if( pM->zText ){
1987     memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
1988     pM->nChar += nNewChar;
1989     pM->zText[pM->nChar] = 0;
1990   }
1991 }
1992 
1993 /*
1994 ** mprintf() works like printf(), but allocations memory to hold the
1995 ** resulting string and returns a pointer to the allocated memory.  Use
1996 ** free() to release the memory allocated.
1997 */
mprintf(const char * zFormat,...)1998 char *mprintf(const char *zFormat, ...){
1999   va_list ap;
2000   struct sgMprintf sMprintf;
2001   char *zNew;
2002   char zBuf[200];
2003 
2004   sMprintf.nChar = 0;
2005   sMprintf.nAlloc = sizeof(zBuf);
2006   sMprintf.zText = zBuf;
2007   sMprintf.zBase = zBuf;
2008   va_start(ap,zFormat);
2009   vxprintf(mout,&sMprintf,zFormat,ap);
2010   va_end(ap);
2011   sMprintf.zText[sMprintf.nChar] = 0;
2012   if( sMprintf.zText==sMprintf.zBase ){
2013     zNew = malloc( sMprintf.nChar+1 );
2014     if( zNew ) memcpy(zNew, zBuf, sMprintf.nChar+1);
2015   }else{
2016     zNew = realloc(sMprintf.zText,sMprintf.nChar+1);
2017     if( zNew==0 ){
2018       free(sMprintf.zText);
2019     }
2020   }
2021   if( zNew==0 ) exit(1);
2022   return zNew;
2023 }
2024 
2025 /* This is the varargs version of mprintf.
2026 */
vmprintf(const char * zFormat,va_list ap)2027 char *vmprintf(const char *zFormat, va_list ap){
2028   struct sgMprintf sMprintf;
2029   char zBuf[200];
2030   sMprintf.nChar = 0;
2031   sMprintf.zText = zBuf;
2032   sMprintf.nAlloc = sizeof(zBuf);
2033   sMprintf.zBase = zBuf;
2034   vxprintf(mout,&sMprintf,zFormat,ap);
2035   sMprintf.zText[sMprintf.nChar] = 0;
2036   if( sMprintf.zText==sMprintf.zBase ){
2037     sMprintf.zText = malloc( sMprintf.nChar+1 );
2038     if( sMprintf.zText ) memcpy(sMprintf.zText, zBuf, sMprintf.nChar+1);
2039   }else{
2040     char *z = realloc(sMprintf.zText,sMprintf.nChar+1);
2041     if( z==0 ){
2042       free(sMprintf.zText);
2043     }
2044     sMprintf.zText = z;
2045   }
2046   if( sMprintf.zText==0 ) exit(1);
2047   return sMprintf.zText;
2048 }
2049 
2050 /*
2051 ** This function implements the callback from vxprintf.
2052 **
2053 ** This routine add nNewChar characters of text in zNewText to
2054 ** the sgMprintf structure pointed to by "arg". Unlink mout(), it
2055 ** doesn't grow the buffer, but truncates the output.
2056 */
bout(void * arg,char * zNewText,int nNewChar)2057 static void bout(void *arg, char *zNewText, int nNewChar){
2058   struct sgMprintf *pM = (struct sgMprintf*)arg;
2059   if( pM->nChar + nNewChar + 1 <= pM->nAlloc ){
2060     memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
2061     pM->zText[pM->nChar+nNewChar] = 0;
2062   }
2063   pM->nChar += nNewChar;
2064 }
2065 
2066 /*
2067 ** bprintf() works like snprintf(), but uses the more advanced formatting
2068 ** of vxprintf(). Returns the number of bytes needed to write the full
2069 ** formatted string. Formatted buffer is always NUL terminated.
2070 */
bprintf(char * zBuf,int nBuflen,const char * zFormat,...)2071 int bprintf(char* zBuf, int nBuflen, const char *zFormat, ...){
2072   va_list ap;
2073   struct sgMprintf sMprintf;
2074 
2075   if( nBuflen <= 0 ) return -1;
2076 
2077   sMprintf.nChar = 0;
2078   sMprintf.nAlloc = nBuflen;
2079   sMprintf.zText = zBuf;
2080 
2081   /* bout() NUL terminates... _if_ it's called */
2082   sMprintf.zText[0] = 0;
2083 
2084   va_start(ap,zFormat);
2085   vxprintf(bout,&sMprintf,zFormat,ap);
2086   va_end(ap);
2087 
2088   return sMprintf.nChar;
2089 }
2090 
2091 /*
2092 ** appendf() is basically an accumulating version of bprintf. Each call
2093 ** will append a NUL terminated to the previous output. If nCurlen is
2094 ** NULL, the function will calculate the current length of the buffer itself
2095 ** (but it _does_ assume that it's NUL terminated).
2096 */
appendf(char * zBuf,int * nCurlen,int nBuflen,const char * zFormat,...)2097 int appendf(char* zBuf, int* nCurlen, int nBuflen, const char *zFormat, ...){
2098   va_list ap;
2099   struct sgMprintf sMprintf;
2100 
2101   if( nBuflen <= 0 ) return -1;
2102 
2103   sMprintf.nChar = nCurlen ? *nCurlen : strlen(zBuf);
2104   sMprintf.nAlloc = nBuflen;
2105   sMprintf.zText = zBuf;
2106 
2107   if( sMprintf.nChar<nBuflen ){
2108     /* bout() NUL terminates... _if_ it's called */
2109     sMprintf.zText[sMprintf.nChar] = 0;
2110   }
2111 
2112   va_start(ap,zFormat);
2113   vxprintf(bout,&sMprintf,zFormat,ap);
2114   va_end(ap);
2115 
2116   if( nCurlen ) *nCurlen = sMprintf.nChar;
2117   return sMprintf.nChar;
2118 }
2119 
2120 /*
2121 ** This function implements the callback from vxprintf.
2122 **
2123 ** This routine sends nNewChar characters of text in zNewText to
2124 ** CGI reply content buffer.
2125 */
sout(void * NotUsed,char * zNewText,int nNewChar)2126 static void sout(void *NotUsed, char *zNewText, int nNewChar){
2127   cgi_append_content(zNewText, nNewChar);
2128 }
2129 
2130 /*
2131 ** This routine works like "printf" except that it has the
2132 ** extra formatting capabilities such as %h and %t.
2133 */
cgi_printf(const char * zFormat,...)2134 void cgi_printf(const char *zFormat, ...){
2135   va_list ap;
2136   va_start(ap,zFormat);
2137   vxprintf(sout,0,zFormat,ap);
2138   va_end(ap);
2139 }
2140 
2141 /*
2142 ** This routine works like "vprintf" except that it has the
2143 ** extra formatting capabilities such as %h and %t.
2144 */
cgi_vprintf(const char * zFormat,va_list ap)2145 void cgi_vprintf(const char *zFormat, va_list ap){
2146   vxprintf(sout,0,zFormat,ap);
2147 }
2148 
2149 /*
2150 ** Make the given string safe for HTML by converting every "<" into "&lt;",
2151 ** every ">" into "&gt;" and every "&" into "&amp;".  Return a pointer
2152 ** to a new string obtained from malloc().
2153 **
2154 ** We also encode " as &quot; so that it can appear as an argument
2155 ** to markup.
2156 */
htmlize(const char * zIn,int n)2157 char *htmlize(const char *zIn, int n){
2158   int c;
2159   int i = 0;
2160   int count = 0;
2161   char *zOut;
2162 
2163   if( n<0 ) n = strlen(zIn);
2164   while( i<n && (c = zIn[i])!=0 ){
2165     switch( c ){
2166       case '<':   count += 4;       break;
2167       case '>':   count += 4;       break;
2168       case '&':   count += 5;       break;
2169       case '"':   count += 6;       break;
2170       default:    count++;          break;
2171     }
2172     i++;
2173   }
2174   i = 0;
2175   zOut = malloc( count+1 );
2176   if( zOut==0 ) return 0;
2177   while( n-->0 && (c = *zIn)!=0 ){
2178     switch( c ){
2179       case '<':
2180         zOut[i++] = '&';
2181         zOut[i++] = 'l';
2182         zOut[i++] = 't';
2183         zOut[i++] = ';';
2184         break;
2185       case '>':
2186         zOut[i++] = '&';
2187         zOut[i++] = 'g';
2188         zOut[i++] = 't';
2189         zOut[i++] = ';';
2190         break;
2191       case '&':
2192         zOut[i++] = '&';
2193         zOut[i++] = 'a';
2194         zOut[i++] = 'm';
2195         zOut[i++] = 'p';
2196         zOut[i++] = ';';
2197         break;
2198       case '"':
2199         zOut[i++] = '&';
2200         zOut[i++] = 'q';
2201         zOut[i++] = 'u';
2202         zOut[i++] = 'o';
2203         zOut[i++] = 't';
2204         zOut[i++] = ';';
2205         break;
2206       default:
2207         zOut[i++] = c;
2208         break;
2209     }
2210     zIn++;
2211   }
2212   zOut[i] = 0;
2213   return zOut;
2214 }
2215 
2216 
2217 /*
2218 ** Encode a string for HTTP.  This means converting lots of
2219 ** characters into the "%HH" where H is a hex digit.  It also
2220 ** means converting spaces to "+".
2221 **
2222 ** This is the opposite of DeHttpizeString below.
2223 */
EncodeHttp(const char * zIn,int n,int encodeSlash)2224 static char *EncodeHttp(const char *zIn, int n, int encodeSlash){
2225   int c;
2226   int i = 0;
2227   int count = 0;
2228   char *zOut;
2229   int other;
2230 # define IsSafeChar(X)  \
2231      (isalnum(X) || (X)=='.' || (X)=='$' || (X)=='-' || (X)=='_' || (X)==other)
2232 
2233   if( zIn==0 ) return 0;
2234   if( n<0 ) n = strlen(zIn);
2235   other = encodeSlash ? 'a' : '/';
2236   while( i<n && (c = zIn[i])!=0 ){
2237     if( IsSafeChar(c) || c==' ' ){
2238       count++;
2239     }else{
2240       count += 3;
2241     }
2242     i++;
2243   }
2244   i = 0;
2245   zOut = malloc( count+1 );
2246   if( zOut==0 ) return 0;
2247   while( n-->0 && (c = *zIn)!=0 ){
2248     if( IsSafeChar(c) ){
2249       zOut[i++] = c;
2250     }else if( c==' ' ){
2251       zOut[i++] = '+';
2252     }else{
2253       zOut[i++] = '%';
2254       zOut[i++] = "0123456789ABCDEF"[(c>>4)&0xf];
2255       zOut[i++] = "0123456789ABCDEF"[c&0xf];
2256     }
2257     zIn++;
2258   }
2259   zOut[i] = 0;
2260   return zOut;
2261 }
2262 
2263 /*
2264 ** Convert the input string into a form that is suitable for use as
2265 ** a token in the HTTP protocol.  Spaces are encoded as '+' and special
2266 ** characters are encoded as "%HH" where HH is a two-digit hexidecimal
2267 ** representation of the character.  The "/" character is encoded
2268 ** as "%2F".
2269 */
httpize(const char * z,int n)2270 char *httpize(const char *z, int n){
2271   return EncodeHttp(z, n, 1);
2272 }
2273 
2274 /*
2275 ** Convert the input string into a form that is suitable for use as
2276 ** a token in the HTTP protocol.  Spaces are encoded as '+' and special
2277 ** characters are encoded as "%HH" where HH is a two-digit hexidecimal
2278 ** representation of the character.  The "/" character is not encoded
2279 ** by this routine.
2280 */
urlize(const char * z,int n)2281 char *urlize(const char *z, int n){
2282   return EncodeHttp(z, n, 0);
2283 }
2284 
2285 /*
2286 ** Convert a single HEX digit to an integer
2287 */
AsciiToHex(int c)2288 static int AsciiToHex(int c){
2289   if( c>='a' && c<='f' ){
2290     c += 10 - 'a';
2291   }else if( c>='A' && c<='F' ){
2292     c += 10 - 'A';
2293   }else if( c>='0' && c<='9' ){
2294     c -= '0';
2295   }else{
2296     c = 0;
2297   }
2298   return c;
2299 }
2300 
2301 /*
2302 ** Remove the HTTP encodings from a string.  The conversion is done
2303 ** in-place.
2304 */
dehttpize(char * z)2305 void dehttpize(char *z){
2306   int i, j;
2307   i = j = 0;
2308   while( z[i] ){
2309     switch( z[i] ){
2310       case '%':
2311         if( z[i+1] && z[i+2] ){
2312           z[j] = AsciiToHex(z[i+1]) << 4;
2313           z[j] |= AsciiToHex(z[i+2]);
2314           i += 2;
2315         }
2316         break;
2317       case '+':
2318         z[j] = ' ';
2319         break;
2320       default:
2321         z[j] = z[i];
2322         break;
2323     }
2324     i++;
2325     j++;
2326   }
2327   z[j] = 0;
2328 }
2329 
2330 /*
2331 ** The characters used for HTTP base64 encoding.
2332 */
2333 static unsigned char zBase[] =
2334   "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";
2335 
2336 /*
2337 ** Encode a string using a base-64 encoding.
2338 ** The encoding can be reversed using the <b>decode64</b> function.
2339 **
2340 ** Space to hold the result comes from malloc().
2341 */
encode64(const unsigned char * zData,int nData)2342 unsigned char *encode64(const unsigned char *zData, int nData){
2343   unsigned char *z64;
2344   int i, n;
2345 
2346   if( nData<=0 ){
2347     nData = strlen((const char *)zData);
2348   }
2349   z64 = malloc( (nData*4)/3 + 6 );
2350   if(z64==0) return 0;
2351   for(i=n=0; i+2<nData; i+=3){
2352     z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
2353     z64[n++] = zBase[ ((zData[i]<<4) & 0x30) | ((zData[i+1]>>4) & 0x0f) ];
2354     z64[n++] = zBase[ ((zData[i+1]<<2) & 0x3c) | ((zData[i+2]>>6) & 0x03) ];
2355     z64[n++] = zBase[ zData[i+2] & 0x3f ];
2356   }
2357   if( i+1<nData ){
2358     z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
2359     z64[n++] = zBase[ ((zData[i]<<4) & 0x30) | ((zData[i+1]>>4) & 0x0f) ];
2360     z64[n++] = zBase[ ((zData[i+1]<<2) & 0x3c) ];
2361   }else if( i<nData ){
2362     z64[n++] = zBase[ (zData[i]>>2) & 0x3f ];
2363     z64[n++] = zBase[ ((zData[i]<<4) & 0x30) ];
2364   }
2365   z64[n] = 0;
2366   return z64;
2367 }
2368 
2369 /*
2370 ** This function treats its input as a base-64 string and returns the
2371 ** decoded value of that string.  Characters of input that are not
2372 ** valid base-64 characters (such as spaces and newlines) are ignored.
2373 **
2374 ** Space to hold the decoded string is obtained from malloc().
2375 */
decode64(const unsigned char * z64)2376 unsigned char *decode64(const unsigned char *z64){
2377   unsigned char *zData;
2378   int n64;
2379   int i, j;
2380   int a, b, c, d;
2381   static int isInit = 0;
2382   static int trans[128];
2383 
2384   if( !isInit ){
2385     for(i=0; i<128; i++){ trans[i] = 0; }
2386     for(i=0; zBase[i]; i++){ trans[zBase[i] & 0x7f] = i; }
2387     isInit = 1;
2388   }
2389   n64 = strlen((const char *)z64);
2390   while( n64>0 && z64[n64-1]=='=' ) n64--;
2391   zData = malloc( (n64*3)/4 + 4 );
2392   if( zData==0 ) return 0;
2393   for(i=j=0; i+3<n64; i+=4){
2394     a = trans[z64[i] & 0x7f];
2395     b = trans[z64[i+1] & 0x7f];
2396     c = trans[z64[i+2] & 0x7f];
2397     d = trans[z64[i+3] & 0x7f];
2398     zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
2399     zData[j++] = ((b<<4) & 0xf0) | ((c>>2) & 0x0f);
2400     zData[j++] = ((c<<6) & 0xc0) | (d & 0x3f);
2401   }
2402   if( i+2<n64 ){
2403     a = trans[z64[i] & 0x7f];
2404     b = trans[z64[i+1] & 0x7f];
2405     c = trans[z64[i+2] & 0x7f];
2406     zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
2407     zData[j++] = ((b<<4) & 0xf0) | ((c>>2) & 0x0f);
2408   }else if( i+1<n64 ){
2409     a = trans[z64[i] & 0x7f];
2410     b = trans[z64[i+1] & 0x7f];
2411     zData[j++] = ((a<<2) & 0xfc) | ((b>>4) & 0x03);
2412   }
2413   zData[j] = 0;
2414   return zData;
2415 }
2416 
2417 /*
2418 ** Send a reply indicating that the HTTP request was malformed
2419 */
malformed_request(void)2420 static void malformed_request(void){
2421   cgi_set_status(501, "Not Implemented");
2422   cgi_printf(
2423     "<html><body>Unrecognized HTTP Request</body></html>\n"
2424   );
2425   cgi_reply();
2426   exit(0);
2427 }
2428 
2429 /*
2430 ** Remove the first space-delimited token from a string and return
2431 ** a pointer to it.  Add a NULL to the string to terminate the token.
2432 ** Make *zLeftOver point to the start of the next token.
2433 */
extract_token(char * zInput,char ** zLeftOver)2434 static char *extract_token(char *zInput, char **zLeftOver){
2435   char *zResult = 0;
2436   if( zInput==0 ){
2437     if( zLeftOver ) *zLeftOver = 0;
2438     return 0;
2439   }
2440   while( isspace(*zInput) ){ zInput++; }
2441   zResult = zInput;
2442   while( *zInput && !isspace(*zInput) ){ zInput++; }
2443   if( *zInput ){
2444     *zInput = 0;
2445     zInput++;
2446     while( isspace(*zInput) ){ zInput++; }
2447   }
2448   if( zLeftOver ){ *zLeftOver = zInput; }
2449   return zResult;
2450 }
2451 
2452 /*
2453 ** This routine handles a single HTTP request which is coming in on
2454 ** standard input and which replies on standard output.
2455 */
cgi_handle_http_request(void)2456 void cgi_handle_http_request(void){
2457   char *z, *zToken;
2458   int i;
2459   struct sockaddr_in remoteName;
2460   size_t size = sizeof(struct sockaddr_in);
2461   char zLine[2000];     /* A single line of input. */
2462 
2463   fullHttpReply = 1;
2464   if( fgets(zLine, sizeof(zLine), stdin)==0 ){
2465     malformed_request();
2466   }
2467   zToken = extract_token(zLine, &z);
2468   if( zToken==0 ){
2469     malformed_request();
2470   }
2471   if( strcmp(zToken,"GET")!=0 && strcmp(zToken,"POST")!=0
2472       && strcmp(zToken,"HEAD")!=0 ){
2473     malformed_request();
2474   }
2475   putenv("GATEWAY_INTERFACE=CGI/1.0");
2476   putenv(mprintf("REQUEST_METHOD=%s",zToken));
2477   zToken = extract_token(z, &z);
2478   if( zToken==0 ){
2479     malformed_request();
2480   }
2481   putenv(mprintf("REQUEST_URI=%s", zToken));
2482   for(i=0; zToken[i] && zToken[i]!='?'; i++){}
2483   if( zToken[i] ) zToken[i++] = 0;
2484   putenv(mprintf("PATH_INFO=%s", zToken));
2485   putenv(mprintf("QUERY_STRING=%s", &zToken[i]));
2486   if( getpeername(fileno(stdin), (struct sockaddr*)&remoteName, &size)>=0 ){
2487     putenv(mprintf("REMOTE_ADDR=%s", inet_ntoa(remoteName.sin_addr)));
2488   }
2489 
2490   /* Get all the optional fields that follow the first line.
2491   */
2492   while( fgets(zLine,sizeof(zLine),stdin) ){
2493     char *zFieldName;
2494     char *zVal;
2495 
2496     zFieldName = extract_token(zLine,&zVal);
2497     if( zFieldName==0 || *zFieldName==0 ) break;
2498     while( isspace(*zVal) ){ zVal++; }
2499     i = strlen(zVal);
2500     while( i>0 && isspace(zVal[i-1]) ){ i--; }
2501     zVal[i] = 0;
2502     for(i=0; zFieldName[i]; i++){ zFieldName[i] = tolower(zFieldName[i]); }
2503     if( strcmp(zFieldName,"user-agent:")==0 ){
2504       putenv(mprintf("HTTP_USER_AGENT=%s", zVal));
2505     }else if( strcmp(zFieldName,"content-length:")==0 ){
2506       putenv(mprintf("CONTENT_LENGTH=%s", zVal));
2507     }else if( strcmp(zFieldName,"referer:")==0 ){
2508       putenv(mprintf("HTTP_REFERER=%s", zVal));
2509     }else if( strcmp(zFieldName,"host:")==0 ){
2510       putenv(mprintf("HTTP_HOST=%s", zVal));
2511     }else if( strcmp(zFieldName,"content-type:")==0 ){
2512       putenv(mprintf("CONTENT_TYPE=%s", zVal));
2513     }else if( strcmp(zFieldName,"cookie:")==0 ){
2514       putenv(mprintf("HTTP_COOKIE=%s", zVal));
2515     }else if( strcmp(zFieldName,"if-none-match:")==0 ){
2516       putenv(mprintf("HTTP_IF_NONE_MATCH=%s", zVal));
2517     }else if( strcmp(zFieldName,"if-modified-since:")==0 ){
2518       putenv(mprintf("HTTP_IF_MODIFIED_SINCE=%s", zVal));
2519     }
2520   }
2521 
2522   cgi_init();
2523 }
2524 
2525 /*
2526 ** Maximum number of child processes that we can have running
2527 ** at one time before we start slowing things down.
2528 */
2529 #define MAX_PARALLEL 2
2530 
2531 /*
2532 ** Implement an HTTP server daemon.
2533 */
cgi_http_server(int iPort)2534 void cgi_http_server(int iPort){
2535   int listener;                /* The server socket */
2536   int connection;              /* A socket for each individual connection */
2537   fd_set readfds;              /* Set of file descriptors for select() */
2538   size_t lenaddr;              /* Length of the inaddr structure */
2539   int child;                   /* PID of the child process */
2540   int nchildren = 0;           /* Number of child processes */
2541   struct timeval delay;        /* How long to wait inside select() */
2542   struct sockaddr_in inaddr;   /* The socket address */
2543   int opt = 1;                 /* setsockopt flag */
2544 
2545   memset(&inaddr, 0, sizeof(inaddr));
2546   inaddr.sin_family = AF_INET;
2547   inaddr.sin_addr.s_addr = INADDR_ANY;
2548   inaddr.sin_port = htons(iPort);
2549   listener = socket(AF_INET, SOCK_STREAM, 0);
2550   if( listener<0 ){
2551     fprintf(stderr,"Can't create a socket\n");
2552     exit(1);
2553   }
2554 
2555   /* if we can't terminate nicely, at least allow the socket to be reused */
2556   setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
2557 
2558   if( bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr))<0 ){
2559     fprintf(stderr,"Can't bind to port %d\n", iPort);
2560     exit(1);
2561   }
2562   listen(listener,10);
2563   while( 1 ){
2564     if( nchildren>MAX_PARALLEL ){
2565       /* Slow down if connections are arriving too fast */
2566       sleep( nchildren-MAX_PARALLEL );
2567     }
2568     delay.tv_sec = 60;
2569     delay.tv_usec = 0;
2570     FD_ZERO(&readfds);
2571     FD_SET( listener, &readfds);
2572     if( select( listener+1, &readfds, 0, 0, &delay) ){
2573       lenaddr = sizeof(inaddr);
2574       connection = accept(listener, (struct sockaddr*)&inaddr, &lenaddr);
2575       if( connection>=0 ){
2576         child = fork();
2577         if( child!=0 ){
2578           if( child>0 ) nchildren++;
2579           close(connection);
2580         }else{
2581           close(0);
2582           dup(connection);
2583           close(1);
2584           dup(connection);
2585           close(2);
2586           dup(connection);
2587           close(connection);
2588           return;
2589         }
2590       }
2591     }
2592     /* Bury dead children */
2593     while( waitpid(0, 0, WNOHANG)>0 ){
2594       nchildren--;
2595     }
2596   }
2597   /* NOT REACHED */
2598   exit(1);
2599 }
2600 
2601 /*
2602 ** Returns an RFC822-formatted time string suitable for HTTP headers, among
2603 ** other things.
2604 ** Returned timezone is always GMT as required by HTTP/1.1 specification.
2605 **
2606 ** See http://www.faqs.org/rfcs/rfc822.html, section 5
2607 ** and http://www.faqs.org/rfcs/rfc2616.html, section 3.3.
2608 */
cgi_rfc822_datestamp(time_t now)2609 char *cgi_rfc822_datestamp(time_t now){
2610   static char *azDays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0};
2611   static char *azMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
2612                              "Aug", "Sep", "Oct", "Nov", "Dec", 0};
2613   struct tm *pTm;
2614   pTm = gmtime(&now);
2615   if( pTm==0 ) return "";
2616   return mprintf("%s, %d %s %02d %02d:%02d:%02d GMT",
2617                  azDays[pTm->tm_wday], pTm->tm_mday, azMonths[pTm->tm_mon],
2618                  pTm->tm_year+1900, pTm->tm_hour, pTm->tm_min, pTm->tm_sec);
2619 }
2620 
2621 /*
2622 ** Parse an RFC822-formatted timestamp as we'd expect from HTTP and return
2623 ** a Unix epoch time. <= zero is returned on failure.
2624 **
2625 ** Note that this won't handle all the _allowed_ HTTP formats, just the
2626 ** most popular one (the one generated by cgi_rfc822_datestamp(), actually).
2627 */
cgi_rfc822_parsedate(const char * zDate)2628 time_t cgi_rfc822_parsedate(const char *zDate){
2629   static char *azMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
2630                              "Aug", "Sep", "Oct", "Nov", "Dec", 0};
2631   struct tm t;
2632   char zIgnore[16];
2633   char zMonth[16];
2634 
2635   memset(&t, 0, sizeof(t));
2636   if( 7==sscanf(zDate, "%12[A-Za-z,] %d %12[A-Za-z] %d %d:%d:%d", zIgnore,
2637                        &t.tm_mday, zMonth, &t.tm_year, &t.tm_hour, &t.tm_min,
2638                        &t.tm_sec)){
2639 
2640     if( t.tm_year > 1900 ) t.tm_year -= 1900;
2641     for(t.tm_mon=0; azMonths[t.tm_mon]; t.tm_mon++){
2642       if( !strncasecmp( azMonths[t.tm_mon], zMonth, 3 )){
2643         return mkgmtime(&t);
2644       }
2645     }
2646   }
2647 
2648   return 0;
2649 }
2650 
2651 /*
2652 ** Check the objectTime against the If-Modified-Since request header. If the
2653 ** object time isn't any newer than the header, we immediately send back
2654 ** a 304 reply and exit.
2655 */
cgi_modified_since(time_t objectTime)2656 void cgi_modified_since(time_t objectTime){
2657   const char *zIf = getenv("HTTP_IF_MODIFIED_SINCE");
2658   if( zIf==0 ) return;
2659   if( objectTime > cgi_rfc822_parsedate(zIf) ) return;
2660   cgi_set_status(304,"Not Modified");
2661   cgi_reset_content();
2662   cgi_reply();
2663   exit(0);
2664 }
2665