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> </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> </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> </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> </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> </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> </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 "<",
2151 ** every ">" into ">" and every "&" into "&". Return a pointer
2152 ** to a new string obtained from malloc().
2153 **
2154 ** We also encode " as " 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