00001
00002
00003
00004
00005
00006
00007
00008
00009 #define cgicTempDir "/tmp"
00010
00011 #if CGICDEBUG
00012 #define CGICDEBUGSTART \
00013 { \
00014 FILE *dout; \
00015 dout = fopen("/home/boutell/public_html/debug", "a"); \
00016
00017 #define CGICDEBUGEND \
00018 fclose(dout); \
00019 }
00020 #else
00021 #define CGICDEBUGSTART
00022 #define CGICDEBUGEND
00023 #endif
00024
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <ctype.h>
00028 #include <stdlib.h>
00029 #include <time.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032
00033 #ifdef WIN32
00034 #include <io.h>
00035
00036
00037 #include <fcntl.h>
00038
00039 #else
00040 #include <unistd.h>
00041 #endif
00042 #include "cgic.h"
00043
00044 #define cgiStrEq(a, b) (!strcmp((a), (b)))
00045
00046 char *cgiServerSoftware;
00047 char *cgiServerName;
00048 char *cgiGatewayInterface;
00049 char *cgiServerProtocol;
00050 char *cgiServerPort;
00051 char *cgiRequestMethod;
00052 char *cgiPathInfo;
00053 char *cgiPathTranslated;
00054 char *cgiScriptName;
00055 char *cgiQueryString;
00056 char *cgiRemoteHost;
00057 char *cgiRemoteAddr;
00058 char *cgiAuthType;
00059 char *cgiRemoteUser;
00060 char *cgiRemoteIdent;
00061 char cgiContentTypeData[1024];
00062 char *cgiContentType = cgiContentTypeData;
00063 char *cgiMultipartBoundary;
00064 char *cgiCookie;
00065 int cgiContentLength;
00066 char *cgiAccept;
00067 char *cgiUserAgent;
00068 char *cgiReferrer;
00069
00070 FILE *cgiIn;
00071 FILE *cgiOut;
00072
00073
00074 static int cgiRestored = 0;
00075
00076 static void cgiGetenv(char **s, char *var);
00077
00078 typedef enum {
00079 cgiParseSuccess,
00080 cgiParseMemory,
00081 cgiParseIO
00082 } cgiParseResultType;
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092 typedef struct cgiFormEntryStruct {
00093 char *attr;
00094
00095
00096
00097 char *value;
00098
00099
00100
00101
00102 int valueLength;
00103 char *fileName;
00104 char *contentType;
00105
00106 char *tfileName;
00107 struct cgiFormEntryStruct *next;
00108 } cgiFormEntry;
00109
00110
00111 static cgiFormEntry *cgiFormEntryFirst;
00112
00113 static cgiParseResultType cgiParseGetFormInput();
00114 static cgiParseResultType cgiParsePostFormInput();
00115 static cgiParseResultType cgiParsePostMultipartInput();
00116 static cgiParseResultType cgiParseFormInput(char *data, int length);
00117 static void cgiSetupConstants();
00118 static void cgiFreeResources();
00119 static int cgiStrEqNc(char *s1, char *s2);
00120 static int cgiStrBeginsNc(char *s1, char *s2);
00121
00122 int main(int argc, char *argv[]) {
00123 int result;
00124 char *cgiContentLengthString;
00125 char *e;
00126 cgiSetupConstants();
00127 cgiGetenv(&cgiServerSoftware, "SERVER_SOFTWARE");
00128 cgiGetenv(&cgiServerName, "SERVER_NAME");
00129 cgiGetenv(&cgiGatewayInterface, "GATEWAY_INTERFACE");
00130 cgiGetenv(&cgiServerProtocol, "SERVER_PROTOCOL");
00131 cgiGetenv(&cgiServerPort, "SERVER_PORT");
00132 cgiGetenv(&cgiRequestMethod, "REQUEST_METHOD");
00133 cgiGetenv(&cgiPathInfo, "PATH_INFO");
00134 cgiGetenv(&cgiPathTranslated, "PATH_TRANSLATED");
00135 cgiGetenv(&cgiScriptName, "SCRIPT_NAME");
00136 cgiGetenv(&cgiQueryString, "QUERY_STRING");
00137 cgiGetenv(&cgiRemoteHost, "REMOTE_HOST");
00138 cgiGetenv(&cgiRemoteAddr, "REMOTE_ADDR");
00139 cgiGetenv(&cgiAuthType, "AUTH_TYPE");
00140 cgiGetenv(&cgiRemoteUser, "REMOTE_USER");
00141 cgiGetenv(&cgiRemoteIdent, "REMOTE_IDENT");
00142
00143
00144 e = getenv("CONTENT_TYPE");
00145 if (e) {
00146 if (strlen(e) < sizeof(cgiContentTypeData)) {
00147 strcpy(cgiContentType, e);
00148 } else {
00149
00150
00151 strncpy(cgiContentType, e, sizeof(cgiContentTypeData));
00152 cgiContentType[sizeof(cgiContentTypeData) - 1] = '\0';
00153 }
00154 } else {
00155 cgiContentType[0] = '\0';
00156 }
00157
00158 cgiMultipartBoundary = "";
00159
00160
00161
00162
00163 if (strchr(cgiContentType, ';')) {
00164 char *sat = strchr(cgiContentType, ';');
00165 while (sat) {
00166 *sat = '\0';
00167 sat++;
00168 while (isspace(*sat)) {
00169 sat++;
00170 }
00171 if (cgiStrBeginsNc(sat, "boundary=")) {
00172 char *s;
00173 cgiMultipartBoundary = sat + strlen("boundary=");
00174 s = cgiMultipartBoundary;
00175 while ((*s) && (!isspace(*s))) {
00176 s++;
00177 }
00178 *s = '\0';
00179 break;
00180 } else {
00181 sat = strchr(sat, ';');
00182 }
00183 }
00184 }
00185 cgiGetenv(&cgiContentLengthString, "CONTENT_LENGTH");
00186 cgiContentLength = atoi(cgiContentLengthString);
00187 cgiGetenv(&cgiAccept, "HTTP_ACCEPT");
00188 cgiGetenv(&cgiUserAgent, "HTTP_USER_AGENT");
00189 cgiGetenv(&cgiReferrer, "HTTP_REFERER");
00190 cgiGetenv(&cgiCookie, "HTTP_COOKIE");
00191 #ifdef CGICDEBUG
00192 CGICDEBUGSTART
00193 fprintf(dout, "%d\n", cgiContentLength);
00194 fprintf(dout, "%s\n", cgiRequestMethod);
00195 fprintf(dout, "%s\n", cgiContentType);
00196 CGICDEBUGEND
00197 #endif
00198 #ifdef WIN32
00199
00200
00201 _setmode( _fileno( stdin ), _O_BINARY );
00202 _setmode( _fileno( stdout ), _O_BINARY );
00203 #endif
00204 cgiFormEntryFirst = 0;
00205 cgiIn = stdin;
00206 cgiOut = stdout;
00207 cgiRestored = 0;
00208
00209
00210
00211
00212
00213 if (argc) {
00214 if (argv[0]) {
00215 cgiRestored = 0;
00216 }
00217 }
00218
00219
00220 if (cgiStrEqNc(cgiRequestMethod, "post")) {
00221 #ifdef CGICDEBUG
00222 CGICDEBUGSTART
00223 fprintf(dout, "POST recognized\n");
00224 CGICDEBUGEND
00225 #endif
00226 if (cgiStrEqNc(cgiContentType, "application/x-www-form-urlencoded")) {
00227 #ifdef CGICDEBUG
00228 CGICDEBUGSTART
00229 fprintf(dout, "Calling PostFormInput\n");
00230 CGICDEBUGEND
00231 #endif
00232 if (cgiParsePostFormInput() != cgiParseSuccess) {
00233 #ifdef CGICDEBUG
00234 CGICDEBUGSTART
00235 fprintf(dout, "PostFormInput failed\n");
00236 CGICDEBUGEND
00237 #endif
00238 cgiFreeResources();
00239 return -1;
00240 }
00241 #ifdef CGICDEBUG
00242 CGICDEBUGSTART
00243 fprintf(dout, "PostFormInput succeeded\n");
00244 CGICDEBUGEND
00245 #endif
00246 } else if (cgiStrEqNc(cgiContentType, "multipart/form-data")) {
00247 #ifdef CGICDEBUG
00248 CGICDEBUGSTART
00249 fprintf(dout, "Calling PostMultipartInput\n");
00250 CGICDEBUGEND
00251 #endif
00252 if (cgiParsePostMultipartInput() != cgiParseSuccess) {
00253 #ifdef CGICDEBUG
00254 CGICDEBUGSTART
00255 fprintf(dout, "PostMultipartInput failed\n");
00256 CGICDEBUGEND
00257 #endif
00258 cgiFreeResources();
00259 return -1;
00260 }
00261 #ifdef CGICDEBUG
00262 CGICDEBUGSTART
00263 fprintf(dout, "PostMultipartInput succeeded\n");
00264 CGICDEBUGEND
00265 #endif
00266 }
00267 } else if (cgiStrEqNc(cgiRequestMethod, "get")) {
00268
00269
00270 cgiContentLength = strlen(cgiQueryString);
00271 if (cgiParseGetFormInput() != cgiParseSuccess) {
00272 #ifdef CGICDEBUG
00273 CGICDEBUGSTART
00274 fprintf(dout, "GetFormInput failed\n");
00275 CGICDEBUGEND
00276 #endif
00277 cgiFreeResources();
00278 return -1;
00279 } else {
00280 #ifdef CGICDEBUG
00281 CGICDEBUGSTART
00282 fprintf(dout, "GetFormInput succeeded\n");
00283 CGICDEBUGEND
00284 #endif
00285 }
00286 }
00287 result = cgiMain();
00288 cgiFreeResources();
00289 return result;
00290 }
00291
00292 static void cgiGetenv(char **s, char *var){
00293 *s = getenv(var);
00294 if (!(*s)) {
00295 *s = "";
00296 }
00297 }
00298
00299 static cgiParseResultType cgiParsePostFormInput() {
00300 char *input;
00301 cgiParseResultType result;
00302 if (!cgiContentLength) {
00303 return cgiParseSuccess;
00304 }
00305 input = (char *) malloc(cgiContentLength);
00306 if (!input) {
00307 return cgiParseMemory;
00308 }
00309 if (((int) fread(input, 1, cgiContentLength, cgiIn))
00310 != cgiContentLength)
00311 {
00312 return cgiParseIO;
00313 }
00314 result = cgiParseFormInput(input, cgiContentLength);
00315 free(input);
00316 return result;
00317 }
00318
00319
00320
00321
00322
00323 typedef struct {
00324
00325 char putback[1024];
00326
00327
00328
00329 int readPos;
00330
00331
00332
00333
00334
00335 int writePos;
00336
00337
00338 int offset;
00339 } mpStream, *mpStreamPtr;
00340
00341 int mpRead(mpStreamPtr mpp, char *buffer, int len)
00342 {
00343 int ilen = len;
00344 int got = 0;
00345 while (len) {
00346 if (mpp->readPos != mpp->writePos) {
00347 *buffer++ = mpp->putback[mpp->readPos++];
00348 mpp->readPos %= sizeof(mpp->putback);
00349 got++;
00350 len--;
00351 } else {
00352 break;
00353 }
00354 }
00355
00356
00357 if (len > (cgiContentLength - mpp->offset)) {
00358 len = cgiContentLength - mpp->offset;
00359 }
00360 if (len) {
00361 int fgot = fread(buffer, 1, len, cgiIn);
00362 if (fgot >= 0) {
00363 mpp->offset += (got + fgot);
00364 return got + fgot;
00365 } else if (got > 0) {
00366 mpp->offset += got;
00367 return got;
00368 } else {
00369
00370 return fgot;
00371 }
00372 } else if (got) {
00373 return got;
00374 } else if (ilen) {
00375 return EOF;
00376 } else {
00377
00378 return 0;
00379 }
00380 }
00381
00382 void mpPutBack(mpStreamPtr mpp, char *data, int len)
00383 {
00384 mpp->offset -= len;
00385 while (len) {
00386 mpp->putback[mpp->writePos++] = *data++;
00387 mpp->writePos %= sizeof(mpp->putback);
00388 len--;
00389 }
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 static cgiParseResultType afterNextBoundary(mpStreamPtr mpp,
00407 FILE *outf,
00408 char **outP,
00409 int *bodyLengthP,
00410 int first
00411 );
00412
00413 static int readHeaderLine(
00414 mpStreamPtr mpp,
00415 char *attr,
00416 int attrSpace,
00417 char *value,
00418 int valueSpace);
00419
00420 static void decomposeValue(char *value,
00421 char *mvalue, int mvalueSpace,
00422 char **argNames,
00423 char **argValues,
00424 int argValueSpace);
00425
00426
00427
00428
00429
00430
00431
00432 static cgiParseResultType getTempFileName(char *tfileName);
00433
00434 static cgiParseResultType cgiParsePostMultipartInput() {
00435 cgiParseResultType result;
00436 cgiFormEntry *n = 0, *l = 0;
00437 int got;
00438 FILE *outf = 0;
00439 char *out = 0;
00440 char tfileName[1024];
00441 mpStream mp;
00442 mpStreamPtr mpp = ∓
00443 memset(&mp, 0, sizeof(mp));
00444 if (!cgiContentLength) {
00445 return cgiParseSuccess;
00446 }
00447
00448 result = afterNextBoundary(mpp, 0, 0, 0, 1);
00449 if (result == cgiParseIO) {
00450
00451 return cgiParseSuccess;
00452 } else if (result != cgiParseSuccess) {
00453 return result;
00454 }
00455 while (1) {
00456 char d[1024];
00457 char fvalue[1024];
00458 char fname[1024];
00459 int bodyLength = 0;
00460 char ffileName[1024];
00461 char fcontentType[1024];
00462 char attr[1024];
00463 char value[1024];
00464 fvalue[0] = 0;
00465 fname[0] = 0;
00466 ffileName[0] = 0;
00467 fcontentType[0] = 0;
00468 out = 0;
00469 outf = 0;
00470
00471 got = mpRead(mpp, d, 2);
00472 if (got < 2) {
00473
00474 break;
00475 }
00476 if ((d[0] == '-') && (d[1] == '-')) {
00477
00478 break;
00479 }
00480 mpPutBack(mpp, d, 2);
00481
00482 while (readHeaderLine(
00483 mpp, attr, sizeof(attr), value, sizeof(value)))
00484 {
00485 char *argNames[3];
00486 char *argValues[2];
00487
00488
00489 if (cgiStrEqNc(attr, "Content-Disposition")) {
00490 argNames[0] = "name";
00491 argNames[1] = "filename";
00492 argNames[2] = 0;
00493 argValues[0] = fname;
00494 argValues[1] = ffileName;
00495 decomposeValue(value,
00496 fvalue, sizeof(fvalue),
00497 argNames,
00498 argValues,
00499 1024);
00500 } else if (cgiStrEqNc(attr, "Content-Type")) {
00501 argNames[0] = 0;
00502 decomposeValue(value,
00503 fcontentType, sizeof(fcontentType),
00504 argNames,
00505 0,
00506 0);
00507 }
00508 }
00509 if (!cgiStrEqNc(fvalue, "form-data")) {
00510
00511 continue;
00512 }
00513
00514
00515
00516
00517
00518
00519 if (strlen(ffileName)) {
00520 if (getTempFileName(tfileName) != cgiParseSuccess) {
00521 return cgiParseIO;
00522 }
00523 outf = fopen(tfileName, "w+b");
00524 } else {
00525 outf = 0;
00526 tfileName[0] = '\0';
00527 }
00528 result = afterNextBoundary(mpp, outf, &out, &bodyLength, 0);
00529 if (result != cgiParseSuccess) {
00530
00531 if (outf) {
00532 fclose(outf);
00533 unlink(tfileName);
00534 }
00535 if (out) {
00536 free(out);
00537 }
00538 return result;
00539 }
00540
00541 n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));
00542 if (!n) {
00543 goto outOfMemory;
00544 }
00545 memset(n, 0, sizeof(cgiFormEntry));
00546
00547
00548 n->attr = (char *) malloc(strlen(fname) + 1);
00549 if (!n->attr) {
00550 goto outOfMemory;
00551 }
00552 strcpy(n->attr, fname);
00553 if (out) {
00554 n->value = out;
00555 out = 0;
00556 } else if (outf) {
00557 n->value = (char *) malloc(1);
00558 if (!n->value) {
00559 goto outOfMemory;
00560 }
00561 n->value[0] = '\0';
00562 fclose(outf);
00563 }
00564 n->valueLength = bodyLength;
00565 n->next = 0;
00566 if (!l) {
00567 cgiFormEntryFirst = n;
00568 } else {
00569 l->next = n;
00570 }
00571 n->fileName = (char *) malloc(strlen(ffileName) + 1);
00572 if (!n->fileName) {
00573 goto outOfMemory;
00574 }
00575 strcpy(n->fileName, ffileName);
00576 n->contentType = (char *) malloc(strlen(fcontentType) + 1);
00577 if (!n->contentType) {
00578 goto outOfMemory;
00579 }
00580 strcpy(n->contentType, fcontentType);
00581 n->tfileName = (char *) malloc(strlen(tfileName) + 1);
00582 if (!n->tfileName) {
00583 goto outOfMemory;
00584 }
00585 strcpy(n->tfileName, tfileName);
00586
00587 l = n;
00588 }
00589 return cgiParseSuccess;
00590 outOfMemory:
00591 if (n) {
00592 if (n->attr) {
00593 free(n->attr);
00594 }
00595 if (n->value) {
00596 free(n->value);
00597 }
00598 if (n->fileName) {
00599 free(n->fileName);
00600 }
00601 if (n->tfileName) {
00602 free(n->tfileName);
00603 }
00604 if (n->contentType) {
00605 free(n->contentType);
00606 }
00607 free(n);
00608 }
00609 if (out) {
00610 free(out);
00611 }
00612 if (outf) {
00613 fclose(outf);
00614 unlink(tfileName);
00615 }
00616 return cgiParseMemory;
00617 }
00618
00619 static cgiParseResultType getTempFileName(char *tfileName)
00620 {
00621 #ifndef WIN32
00622
00623
00624
00625
00626
00627
00628
00629
00630 int outfd;
00631 strcpy(tfileName, cgicTempDir "/cgicXXXXXX");
00632 outfd = mkstemp(tfileName);
00633 if (outfd == -1) {
00634 return cgiParseIO;
00635 }
00636 close(outfd);
00637
00638 if (chmod(tfileName, 0600) != 0) {
00639 unlink(tfileName);
00640 return cgiParseIO;
00641 }
00642 #else
00643
00644 if (!tmpnam(tfileName)) {
00645 return cgiParseIO;
00646 }
00647 #endif
00648 return cgiParseSuccess;
00649 }
00650
00651
00652 #define APPEND(string, char) \
00653 { \
00654 if ((string##Len + 1) < string##Space) { \
00655 string[string##Len++] = (char); \
00656 } \
00657 }
00658
00659 #define RAPPEND(string, ch) \
00660 { \
00661 if ((string##Len + 1) == string##Space) { \
00662 char *sold = string; \
00663 string##Space *= 2; \
00664 string = (char *) realloc(string, string##Space); \
00665 if (!string) { \
00666 string = sold; \
00667 goto outOfMemory; \
00668 } \
00669 } \
00670 string[string##Len++] = (ch); \
00671 }
00672
00673 #define BAPPEND(ch) \
00674 { \
00675 if (outf) { \
00676 putc(ch, outf); \
00677 outLen++; \
00678 } else if (out) { \
00679 RAPPEND(out, ch); \
00680 } \
00681 }
00682
00683 cgiParseResultType afterNextBoundary(mpStreamPtr mpp, FILE *outf, char **outP,
00684 int *bodyLengthP, int first)
00685 {
00686 int outLen = 0;
00687 int outSpace = 256;
00688 char *out = 0;
00689 cgiParseResultType result;
00690 int boffset;
00691 int got;
00692 char d[2];
00693
00694
00695
00696
00697 char workingBoundaryData[1024];
00698 char *workingBoundary = workingBoundaryData;
00699 int workingBoundaryLength;
00700 if ((!outf) && (outP)) {
00701 out = (char *) malloc(outSpace);
00702 if (!out) {
00703 goto outOfMemory;
00704 }
00705 }
00706 boffset = 0;
00707 sprintf(workingBoundaryData, "\r\n--%s", cgiMultipartBoundary);
00708 if (first) {
00709 workingBoundary = workingBoundaryData + 2;
00710 }
00711 workingBoundaryLength = strlen(workingBoundary);
00712 while (1) {
00713 got = mpRead(mpp, d, 1);
00714 if (got != 1) {
00715
00716 result = cgiParseIO;
00717 goto error;
00718 }
00719 if (d[0] == workingBoundary[boffset]) {
00720
00721
00722
00723 boffset++;
00724 if (boffset == workingBoundaryLength) {
00725 break;
00726 }
00727 } else if (boffset > 0) {
00728
00729
00730
00731
00732
00733
00734
00735 BAPPEND(workingBoundary[0]);
00736 mpPutBack(mpp,
00737 workingBoundary + 1, boffset - 1);
00738 mpPutBack(mpp, d, 1);
00739 boffset = 0;
00740 } else {
00741
00742
00743 BAPPEND(d[0]);
00744 }
00745 }
00746
00747
00748 got = mpRead(mpp, d, 2);
00749 if (got != 2) {
00750 result = cgiParseIO;
00751 goto error;
00752 }
00753 if ((d[0] == '\r') && (d[1] == '\n')) {
00754
00755 } else if (d[0] == '-') {
00756
00757
00758 mpPutBack(mpp, d, 2);
00759 }
00760 if (out && outSpace) {
00761 char *oout = out;
00762 out[outLen] = '\0';
00763 out = (char *) realloc(out, outLen + 1);
00764 if (!out) {
00765
00766
00767
00768 out = oout;
00769 }
00770 *outP = out;
00771 }
00772 if (bodyLengthP) {
00773 *bodyLengthP = outLen;
00774 }
00775 return cgiParseSuccess;
00776 outOfMemory:
00777 result = cgiParseMemory;
00778 if (outP) {
00779 if (out) {
00780 free(out);
00781 }
00782 *outP = '\0';
00783 }
00784 error:
00785 if (bodyLengthP) {
00786 *bodyLengthP = 0;
00787 }
00788 if (out) {
00789 free(out);
00790 }
00791 if (outP) {
00792 *outP = 0;
00793 }
00794 return result;
00795 }
00796
00797 static void decomposeValue(char *value,
00798 char *mvalue, int mvalueSpace,
00799 char **argNames,
00800 char **argValues,
00801 int argValueSpace)
00802 {
00803 char argName[1024];
00804 int argNameSpace = sizeof(argName);
00805 int argNameLen = 0;
00806 int mvalueLen = 0;
00807 char *argValue;
00808 int argNum = 0;
00809 while (argNames[argNum]) {
00810 if (argValueSpace) {
00811 argValues[argNum][0] = '\0';
00812 }
00813 argNum++;
00814 }
00815 while (isspace(*value)) {
00816 value++;
00817 }
00818
00819 if (*value == '\"') {
00820 value++;
00821 while ((*value) && (*value != '\"')) {
00822 APPEND(mvalue, *value);
00823 value++;
00824 }
00825 while ((*value) && (*value != ';')) {
00826 value++;
00827 }
00828 } else {
00829
00830 while ((*value) && (*value != ';')) {
00831 APPEND(mvalue, *value);
00832 value++;
00833 }
00834 }
00835 if (mvalueSpace) {
00836 mvalue[mvalueLen] = '\0';
00837 }
00838 while (*value == ';') {
00839 int argNum;
00840 int argValueLen = 0;
00841
00842 value++;
00843
00844 while ((*value) && (isspace(*value))) {
00845 value++;
00846 }
00847
00848 argNameLen = 0;
00849 while ((*value) && (isalnum(*value))) {
00850 APPEND(argName, *value);
00851 value++;
00852 }
00853 if (argNameSpace) {
00854 argName[argNameLen] = '\0';
00855 }
00856 while ((*value) && isspace(*value)) {
00857 value++;
00858 }
00859 if (*value != '=') {
00860
00861 return;
00862 }
00863 value++;
00864 while ((*value) && isspace(*value)) {
00865 value++;
00866 }
00867
00868 argNum = 0;
00869 argValue = 0;
00870 while (argNames[argNum]) {
00871 if (cgiStrEqNc(argName, argNames[argNum])) {
00872 argValue = argValues[argNum];
00873 break;
00874 }
00875 argNum++;
00876 }
00877
00878 if (*value == '\"') {
00879 value++;
00880 while ((*value) && (*value != '\"')) {
00881 if (argValue) {
00882 APPEND(argValue, *value);
00883 }
00884 value++;
00885 }
00886 while ((*value) && (*value != ';')) {
00887 value++;
00888 }
00889 } else {
00890
00891 while ((*value) && (*value != ';')) {
00892 if (argNames[argNum]) {
00893 APPEND(argValue, *value);
00894 }
00895 value++;
00896 }
00897 }
00898 if (argValueSpace) {
00899 argValue[argValueLen] = '\0';
00900 }
00901 }
00902 }
00903
00904 static int readHeaderLine(
00905 mpStreamPtr mpp,
00906 char *attr,
00907 int attrSpace,
00908 char *value,
00909 int valueSpace)
00910 {
00911 int attrLen = 0;
00912 int valueLen = 0;
00913 int valueFound = 0;
00914 while (1) {
00915 char d[1];
00916 int got = mpRead(mpp, d, 1);
00917 if (got != 1) {
00918 return 0;
00919 }
00920 if (d[0] == '\r') {
00921 got = mpRead(mpp, d, 1);
00922 if (got == 1) {
00923 if (d[0] == '\n') {
00924
00925 } else {
00926 mpPutBack(mpp, d, 1);
00927 }
00928 }
00929 break;
00930 } else if (d[0] == '\n') {
00931 break;
00932 } else if ((d[0] == ':') && attrLen) {
00933 valueFound = 1;
00934 while (mpRead(mpp, d, 1) == 1) {
00935 if (!isspace(d[0])) {
00936 mpPutBack(mpp, d, 1);
00937 break;
00938 }
00939 }
00940 } else if (!valueFound) {
00941 if (!isspace(*d)) {
00942 if (attrLen < (attrSpace - 1)) {
00943 attr[attrLen++] = *d;
00944 }
00945 }
00946 } else if (valueFound) {
00947 if (valueLen < (valueSpace - 1)) {
00948 value[valueLen++] = *d;
00949 }
00950 }
00951 }
00952 if (attrSpace) {
00953 attr[attrLen] = '\0';
00954 }
00955 if (valueSpace) {
00956 value[valueLen] = '\0';
00957 }
00958 if (attrLen && valueLen) {
00959 return 1;
00960 } else {
00961 return 0;
00962 }
00963 }
00964
00965 static cgiParseResultType cgiParseGetFormInput() {
00966 return cgiParseFormInput(cgiQueryString, cgiContentLength);
00967 }
00968
00969 typedef enum {
00970 cgiEscapeRest,
00971 cgiEscapeFirst,
00972 cgiEscapeSecond
00973 } cgiEscapeState;
00974
00975 typedef enum {
00976 cgiUnescapeSuccess,
00977 cgiUnescapeMemory
00978 } cgiUnescapeResultType;
00979
00980 static cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len);
00981
00982 static cgiParseResultType cgiParseFormInput(char *data, int length) {
00983
00984 int pos = 0;
00985 cgiFormEntry *n;
00986 cgiFormEntry *l = 0;
00987 while (pos != length) {
00988 int foundEq = 0;
00989 int foundAmp = 0;
00990 int start = pos;
00991 int len = 0;
00992 char *attr;
00993 char *value;
00994 while (pos != length) {
00995 if (data[pos] == '=') {
00996 foundEq = 1;
00997 pos++;
00998 break;
00999 }
01000 pos++;
01001 len++;
01002 }
01003 if (!foundEq) {
01004 break;
01005 }
01006 if (cgiUnescapeChars(&attr, data+start, len)
01007 != cgiUnescapeSuccess) {
01008 return cgiParseMemory;
01009 }
01010 start = pos;
01011 len = 0;
01012 while (pos != length) {
01013 if (data[pos] == '&') {
01014 foundAmp = 1;
01015 pos++;
01016 break;
01017 }
01018 pos++;
01019 len++;
01020 }
01021
01022
01023 if (cgiUnescapeChars(&value, data+start, len)
01024 != cgiUnescapeSuccess) {
01025 free(attr);
01026 return cgiParseMemory;
01027 }
01028
01029 n = (cgiFormEntry *) malloc(sizeof(cgiFormEntry));
01030 if (!n) {
01031 free(attr);
01032 free(value);
01033 return cgiParseMemory;
01034 }
01035 n->attr = attr;
01036 n->value = value;
01037 n->valueLength = strlen(n->value);
01038 n->fileName = (char *) malloc(1);
01039 if (!n->fileName) {
01040 free(attr);
01041 free(value);
01042 free(n);
01043 return cgiParseMemory;
01044 }
01045 n->fileName[0] = '\0';
01046 n->contentType = (char *) malloc(1);
01047 if (!n->contentType) {
01048 free(attr);
01049 free(value);
01050 free(n->fileName);
01051 free(n);
01052 return cgiParseMemory;
01053 }
01054 n->contentType[0] = '\0';
01055 n->tfileName = (char *) malloc(1);
01056 if (!n->tfileName) {
01057 free(attr);
01058 free(value);
01059 free(n->fileName);
01060 free(n->contentType);
01061 free(n);
01062 return cgiParseMemory;
01063 }
01064 n->tfileName[0] = '\0';
01065 n->next = 0;
01066 if (!l) {
01067 cgiFormEntryFirst = n;
01068 } else {
01069 l->next = n;
01070 }
01071 l = n;
01072 if (!foundAmp) {
01073 break;
01074 }
01075 }
01076 return cgiParseSuccess;
01077 }
01078
01079 static int cgiHexValue[256];
01080
01081 cgiUnescapeResultType cgiUnescapeChars(char **sp, char *cp, int len) {
01082 char *s;
01083 cgiEscapeState escapeState = cgiEscapeRest;
01084 int escapedValue = 0;
01085 int srcPos = 0;
01086 int dstPos = 0;
01087 s = (char *) malloc(len + 1);
01088 if (!s) {
01089 return cgiUnescapeMemory;
01090 }
01091 while (srcPos < len) {
01092 int ch = cp[srcPos];
01093 switch (escapeState) {
01094 case cgiEscapeRest:
01095 if (ch == '%') {
01096 escapeState = cgiEscapeFirst;
01097 } else if (ch == '+') {
01098 s[dstPos++] = ' ';
01099 } else {
01100 s[dstPos++] = ch;
01101 }
01102 break;
01103 case cgiEscapeFirst:
01104 escapedValue = cgiHexValue[ch] << 4;
01105 escapeState = cgiEscapeSecond;
01106 break;
01107 case cgiEscapeSecond:
01108 escapedValue += cgiHexValue[ch];
01109 s[dstPos++] = escapedValue;
01110 escapeState = cgiEscapeRest;
01111 break;
01112 }
01113 srcPos++;
01114 }
01115 s[dstPos] = '\0';
01116 *sp = s;
01117 return cgiUnescapeSuccess;
01118 }
01119
01120 static void cgiSetupConstants() {
01121 int i;
01122 for (i=0; (i < 256); i++) {
01123 cgiHexValue[i] = 0;
01124 }
01125 cgiHexValue['0'] = 0;
01126 cgiHexValue['1'] = 1;
01127 cgiHexValue['2'] = 2;
01128 cgiHexValue['3'] = 3;
01129 cgiHexValue['4'] = 4;
01130 cgiHexValue['5'] = 5;
01131 cgiHexValue['6'] = 6;
01132 cgiHexValue['7'] = 7;
01133 cgiHexValue['8'] = 8;
01134 cgiHexValue['9'] = 9;
01135 cgiHexValue['A'] = 10;
01136 cgiHexValue['B'] = 11;
01137 cgiHexValue['C'] = 12;
01138 cgiHexValue['D'] = 13;
01139 cgiHexValue['E'] = 14;
01140 cgiHexValue['F'] = 15;
01141 cgiHexValue['a'] = 10;
01142 cgiHexValue['b'] = 11;
01143 cgiHexValue['c'] = 12;
01144 cgiHexValue['d'] = 13;
01145 cgiHexValue['e'] = 14;
01146 cgiHexValue['f'] = 15;
01147 }
01148
01149 static void cgiFreeResources() {
01150 cgiFormEntry *c = cgiFormEntryFirst;
01151 cgiFormEntry *n;
01152 while (c) {
01153 n = c->next;
01154 free(c->attr);
01155 free(c->value);
01156 free(c->fileName);
01157 free(c->contentType);
01158 if (strlen(c->tfileName)) {
01159 unlink(c->tfileName);
01160 }
01161 free(c->tfileName);
01162 free(c);
01163 c = n;
01164 }
01165
01166
01167 if (cgiRestored) {
01168 free(cgiServerSoftware);
01169 free(cgiServerName);
01170 free(cgiGatewayInterface);
01171 free(cgiServerProtocol);
01172 free(cgiServerPort);
01173 free(cgiRequestMethod);
01174 free(cgiPathInfo);
01175 free(cgiPathTranslated);
01176 free(cgiScriptName);
01177 free(cgiQueryString);
01178 free(cgiRemoteHost);
01179 free(cgiRemoteAddr);
01180 free(cgiAuthType);
01181 free(cgiRemoteUser);
01182 free(cgiRemoteIdent);
01183 free(cgiContentType);
01184 free(cgiAccept);
01185 free(cgiUserAgent);
01186 free(cgiReferrer);
01187 }
01188
01189
01190 cgiFormEntryFirst = 0;
01191 cgiRestored = 0;
01192 }
01193
01194 static cgiFormResultType cgiFormEntryString(
01195 cgiFormEntry *e, char *result, int max, int newlines);
01196
01197 static cgiFormEntry *cgiFormEntryFindFirst(char *name);
01198 static cgiFormEntry *cgiFormEntryFindNext();
01199
01200 cgiFormResultType cgiFormString(
01201 char *name, char *result, int max) {
01202 cgiFormEntry *e;
01203 e = cgiFormEntryFindFirst(name);
01204 if (!e) {
01205 strcpy(result, "");
01206 return cgiFormNotFound;
01207 }
01208 return cgiFormEntryString(e, result, max, 1);
01209 }
01210
01211 cgiFormResultType cgiFormFileName(
01212 char *name, char *result, int resultSpace)
01213 {
01214 cgiFormEntry *e;
01215 int resultLen = 0;
01216 char *s;
01217 e = cgiFormEntryFindFirst(name);
01218 if (!e) {
01219 strcpy(result, "");
01220 return cgiFormNotFound;
01221 }
01222 s = e->fileName;
01223 while (*s) {
01224 APPEND(result, *s);
01225 s++;
01226 }
01227 if (resultSpace) {
01228 result[resultLen] = '\0';
01229 }
01230 if (!strlen(e->fileName)) {
01231 return cgiFormNoFileName;
01232 } else if (((int) strlen(e->fileName)) > (resultSpace - 1)) {
01233 return cgiFormTruncated;
01234 } else {
01235 return cgiFormSuccess;
01236 }
01237 }
01238
01239 cgiFormResultType cgiFormFileContentType(
01240 char *name, char *result, int resultSpace)
01241 {
01242 cgiFormEntry *e;
01243 int resultLen = 0;
01244 char *s;
01245 e = cgiFormEntryFindFirst(name);
01246 if (!e) {
01247 if (resultSpace) {
01248 result[0] = '\0';
01249 }
01250 return cgiFormNotFound;
01251 }
01252 s = e->contentType;
01253 while (*s) {
01254 APPEND(result, *s);
01255 s++;
01256 }
01257 if (resultSpace) {
01258 result[resultLen] = '\0';
01259 }
01260 if (!strlen(e->contentType)) {
01261 return cgiFormNoContentType;
01262 } else if (((int) strlen(e->contentType)) > (resultSpace - 1)) {
01263 return cgiFormTruncated;
01264 } else {
01265 return cgiFormSuccess;
01266 }
01267 }
01268
01269 cgiFormResultType cgiFormFileSize(
01270 char *name, int *sizeP)
01271 {
01272 cgiFormEntry *e;
01273 e = cgiFormEntryFindFirst(name);
01274 if (!e) {
01275 if (sizeP) {
01276 *sizeP = 0;
01277 }
01278 return cgiFormNotFound;
01279 } else if (!strlen(e->tfileName)) {
01280 if (sizeP) {
01281 *sizeP = 0;
01282 }
01283 return cgiFormNotAFile;
01284 } else {
01285 if (sizeP) {
01286 *sizeP = e->valueLength;
01287 }
01288 return cgiFormSuccess;
01289 }
01290 }
01291
01292 typedef struct cgiFileStruct {
01293 FILE *in;
01294 } cgiFile;
01295
01296 cgiFormResultType cgiFormFileOpen(
01297 char *name, cgiFilePtr *cfpp)
01298 {
01299 cgiFormEntry *e;
01300 cgiFilePtr cfp;
01301 e = cgiFormEntryFindFirst(name);
01302 if (!e) {
01303 *cfpp = 0;
01304 return cgiFormNotFound;
01305 }
01306 if (!strlen(e->tfileName)) {
01307 *cfpp = 0;
01308 return cgiFormNotAFile;
01309 }
01310 cfp = (cgiFilePtr) malloc(sizeof(cgiFile));
01311 if (!cfp) {
01312 *cfpp = 0;
01313 return cgiFormMemory;
01314 }
01315 cfp->in = fopen(e->tfileName, "rb");
01316 if (!cfp->in) {
01317 free(cfp);
01318 return cgiFormIO;
01319 }
01320 *cfpp = cfp;
01321 return cgiFormSuccess;
01322 }
01323
01324 cgiFormResultType cgiFormFileRead(
01325 cgiFilePtr cfp, char *buffer,
01326 int bufferSize, int *gotP)
01327 {
01328 int got = 0;
01329 if (!cfp) {
01330 return cgiFormOpenFailed;
01331 }
01332 got = fread(buffer, 1, bufferSize, cfp->in);
01333 if (got <= 0) {
01334 return cgiFormEOF;
01335 }
01336 *gotP = got;
01337 return cgiFormSuccess;
01338 }
01339
01340 cgiFormResultType cgiFormFileClose(cgiFilePtr cfp)
01341 {
01342 if (!cfp) {
01343 return cgiFormOpenFailed;
01344 }
01345 fclose(cfp->in);
01346 free(cfp);
01347 return cgiFormSuccess;
01348 }
01349
01350 cgiFormResultType cgiFormStringNoNewlines(
01351 char *name, char *result, int max) {
01352 cgiFormEntry *e;
01353 e = cgiFormEntryFindFirst(name);
01354 if (!e) {
01355 strcpy(result, "");
01356 return cgiFormNotFound;
01357 }
01358 return cgiFormEntryString(e, result, max, 0);
01359 }
01360
01361 cgiFormResultType cgiFormStringMultiple(
01362 char *name, char ***result) {
01363 char **stringArray;
01364 cgiFormEntry *e;
01365 int i;
01366 int total = 0;
01367
01368
01369
01370 e = cgiFormEntryFindFirst(name);
01371 if (e != 0) {
01372 do {
01373 total++;
01374 } while ((e = cgiFormEntryFindNext()) != 0);
01375 }
01376 stringArray = (char **) malloc(sizeof(char *) * (total + 1));
01377 if (!stringArray) {
01378 *result = 0;
01379 return cgiFormMemory;
01380 }
01381
01382 for (i=0; (i <= total); i++) {
01383 stringArray[i] = 0;
01384 }
01385
01386 e = cgiFormEntryFindFirst(name);
01387 #ifdef CGICDEBUG
01388 CGICDEBUGSTART
01389 fprintf(dout, "StringMultiple Beginning\n");
01390 CGICDEBUGEND
01391 #endif
01392 if (e) {
01393 i = 0;
01394 do {
01395 int max = (int) (strlen(e->value) + 1);
01396 stringArray[i] = (char *) malloc(max);
01397 if (stringArray[i] == 0) {
01398
01399 cgiStringArrayFree(stringArray);
01400 *result = 0;
01401 return cgiFormMemory;
01402 }
01403 strcpy(stringArray[i], e->value);
01404 cgiFormEntryString(e, stringArray[i], max, 1);
01405 i++;
01406 } while ((e = cgiFormEntryFindNext()) != 0);
01407 *result = stringArray;
01408 #ifdef CGICDEBUG
01409 CGICDEBUGSTART
01410 fprintf(dout, "StringMultiple Succeeding\n");
01411 CGICDEBUGEND
01412 #endif
01413 return cgiFormSuccess;
01414 } else {
01415 *result = stringArray;
01416 #ifdef CGICDEBUG
01417 CGICDEBUGSTART
01418 fprintf(dout, "StringMultiple found nothing\n");
01419 CGICDEBUGEND
01420 #endif
01421 return cgiFormNotFound;
01422 }
01423 }
01424
01425 cgiFormResultType cgiFormStringSpaceNeeded(
01426 char *name, int *result) {
01427 cgiFormEntry *e;
01428 e = cgiFormEntryFindFirst(name);
01429 if (!e) {
01430 *result = 1;
01431 return cgiFormNotFound;
01432 }
01433 *result = ((int) strlen(e->value)) + 1;
01434 return cgiFormSuccess;
01435 }
01436
01437 static cgiFormResultType cgiFormEntryString(
01438 cgiFormEntry *e, char *result, int max, int newlines) {
01439 char *dp, *sp;
01440 int truncated = 0;
01441 int len = 0;
01442 int avail = max-1;
01443 int crCount = 0;
01444 int lfCount = 0;
01445 dp = result;
01446 sp = e->value;
01447 while (1) {
01448 int ch;
01449
01450
01451
01452
01453
01454 ch = *sp;
01455
01456
01457
01458
01459
01460
01461 if ((ch == 13) || (ch == 10)) {
01462 if (ch == 13) {
01463 crCount++;
01464 } else {
01465 lfCount++;
01466 }
01467 } else {
01468 if (crCount || lfCount) {
01469 int lfsAdd = crCount;
01470 if (lfCount > crCount) {
01471 lfsAdd = lfCount;
01472 }
01473
01474 if (!newlines) {
01475 lfsAdd = 0;
01476 }
01477 while (lfsAdd) {
01478 if (len >= avail) {
01479 truncated = 1;
01480 break;
01481 }
01482 *dp = 10;
01483 dp++;
01484 lfsAdd--;
01485 len++;
01486 }
01487 crCount = 0;
01488 lfCount = 0;
01489 }
01490 if (ch == '\0') {
01491
01492 break;
01493 }
01494
01495
01496
01497 if (len >= avail) {
01498 truncated = 1;
01499 break;
01500 }
01501 *dp = ch;
01502 dp++;
01503 len++;
01504 }
01505 sp++;
01506 }
01507 *dp = '\0';
01508 if (truncated) {
01509 return cgiFormTruncated;
01510 } else if (!len) {
01511 return cgiFormEmpty;
01512 } else {
01513 return cgiFormSuccess;
01514 }
01515 }
01516
01517 static int cgiFirstNonspaceChar(char *s);
01518
01519 cgiFormResultType cgiFormInteger(
01520 char *name, int *result, int defaultV) {
01521 cgiFormEntry *e;
01522 int ch;
01523 e = cgiFormEntryFindFirst(name);
01524 if (!e) {
01525 *result = defaultV;
01526 return cgiFormNotFound;
01527 }
01528 if (!strlen(e->value)) {
01529 *result = defaultV;
01530 return cgiFormEmpty;
01531 }
01532 ch = cgiFirstNonspaceChar(e->value);
01533 if (!(isdigit(ch)) && (ch != '-') && (ch != '+')) {
01534 *result = defaultV;
01535 return cgiFormBadType;
01536 } else {
01537 *result = atoi(e->value);
01538 return cgiFormSuccess;
01539 }
01540 }
01541
01542 cgiFormResultType cgiFormIntegerBounded(
01543 char *name, int *result, int min, int max, int defaultV) {
01544 cgiFormResultType error = cgiFormInteger(name, result, defaultV);
01545 if (error != cgiFormSuccess) {
01546 return error;
01547 }
01548 if (*result < min) {
01549 *result = min;
01550 return cgiFormConstrained;
01551 }
01552 if (*result > max) {
01553 *result = max;
01554 return cgiFormConstrained;
01555 }
01556 return cgiFormSuccess;
01557 }
01558
01559 cgiFormResultType cgiFormDouble(
01560 char *name, double *result, double defaultV) {
01561 cgiFormEntry *e;
01562 int ch;
01563 e = cgiFormEntryFindFirst(name);
01564 if (!e) {
01565 *result = defaultV;
01566 return cgiFormNotFound;
01567 }
01568 if (!strlen(e->value)) {
01569 *result = defaultV;
01570 return cgiFormEmpty;
01571 }
01572 ch = cgiFirstNonspaceChar(e->value);
01573 if (!(isdigit(ch)) && (ch != '.') && (ch != '-') && (ch != '+')) {
01574 *result = defaultV;
01575 return cgiFormBadType;
01576 } else {
01577 *result = atof(e->value);
01578 return cgiFormSuccess;
01579 }
01580 }
01581
01582 cgiFormResultType cgiFormDoubleBounded(
01583 char *name, double *result, double min, double max, double defaultV) {
01584 cgiFormResultType error = cgiFormDouble(name, result, defaultV);
01585 if (error != cgiFormSuccess) {
01586 return error;
01587 }
01588 if (*result < min) {
01589 *result = min;
01590 return cgiFormConstrained;
01591 }
01592 if (*result > max) {
01593 *result = max;
01594 return cgiFormConstrained;
01595 }
01596 return cgiFormSuccess;
01597 }
01598
01599 cgiFormResultType cgiFormSelectSingle(
01600 char *name, char **choicesText, int choicesTotal,
01601 int *result, int defaultV)
01602 {
01603 cgiFormEntry *e;
01604 int i;
01605 e = cgiFormEntryFindFirst(name);
01606 #ifdef CGICDEBUG
01607 CGICDEBUGSTART
01608 fprintf(dout, "%d\n", (int) e);
01609 CGICDEBUGEND
01610 #endif
01611 if (!e) {
01612 *result = defaultV;
01613 return cgiFormNotFound;
01614 }
01615 for (i=0; (i < choicesTotal); i++) {
01616 #ifdef CGICDEBUG
01617 CGICDEBUGSTART
01618 fprintf(dout, "%s %s\n", choicesText[i], e->value);
01619 CGICDEBUGEND
01620 #endif
01621 if (cgiStrEq(choicesText[i], e->value)) {
01622 #ifdef CGICDEBUG
01623 CGICDEBUGSTART
01624 fprintf(dout, "MATCH\n");
01625 CGICDEBUGEND
01626 #endif
01627 *result = i;
01628 return cgiFormSuccess;
01629 }
01630 }
01631 *result = defaultV;
01632 return cgiFormNoSuchChoice;
01633 }
01634
01635 cgiFormResultType cgiFormSelectMultiple(
01636 char *name, char **choicesText, int choicesTotal,
01637 int *result, int *invalid)
01638 {
01639 cgiFormEntry *e;
01640 int i;
01641 int hits = 0;
01642 int invalidE = 0;
01643 for (i=0; (i < choicesTotal); i++) {
01644 result[i] = 0;
01645 }
01646 e = cgiFormEntryFindFirst(name);
01647 if (!e) {
01648 *invalid = invalidE;
01649 return cgiFormNotFound;
01650 }
01651 do {
01652 int hit = 0;
01653 for (i=0; (i < choicesTotal); i++) {
01654 if (cgiStrEq(choicesText[i], e->value)) {
01655 result[i] = 1;
01656 hits++;
01657 hit = 1;
01658 break;
01659 }
01660 }
01661 if (!(hit)) {
01662 invalidE++;
01663 }
01664 } while ((e = cgiFormEntryFindNext()) != 0);
01665
01666 *invalid = invalidE;
01667
01668 if (hits) {
01669 return cgiFormSuccess;
01670 } else {
01671 return cgiFormNotFound;
01672 }
01673 }
01674
01675 cgiFormResultType cgiFormCheckboxSingle(
01676 char *name)
01677 {
01678 cgiFormEntry *e;
01679 e = cgiFormEntryFindFirst(name);
01680 if (!e) {
01681 return cgiFormNotFound;
01682 }
01683 return cgiFormSuccess;
01684 }
01685
01686 extern cgiFormResultType cgiFormCheckboxMultiple(
01687 char *name, char **valuesText, int valuesTotal,
01688 int *result, int *invalid)
01689 {
01690
01691 return cgiFormSelectMultiple(name, valuesText,
01692 valuesTotal, result, invalid);
01693 }
01694
01695 cgiFormResultType cgiFormRadio(
01696 char *name,
01697 char **valuesText, int valuesTotal, int *result, int defaultV)
01698 {
01699
01700 return cgiFormSelectSingle(name, valuesText, valuesTotal,
01701 result, defaultV);
01702 }
01703
01704 cgiFormResultType cgiCookieString(
01705 char *name,
01706 char *value,
01707 int space)
01708 {
01709 char *p = cgiCookie;
01710 while (*p) {
01711 char *n = name;
01712
01713
01714
01715
01716
01717
01718 while (*p == *n) {
01719 if ((p == '\0') && (n == '\0')) {
01720
01721 return cgiFormNotFound;
01722 }
01723 p++;
01724 n++;
01725 }
01726 if ((!*n) && (*p == '=')) {
01727 p++;
01728 while ((*p != ';') && (*p != '\0') &&
01729 (space > 1))
01730 {
01731 *value = *p;
01732 value++;
01733 p++;
01734 space--;
01735 }
01736 if (space > 0) {
01737 *value = '\0';
01738 }
01739
01740
01741 if (!(((*p) == ';') || ((*p) == '\0')))
01742 {
01743 return cgiFormTruncated;
01744 } else {
01745 return cgiFormSuccess;
01746 }
01747 } else {
01748
01749 while (*p) {
01750 if (*p == ';') {
01751 break;
01752 }
01753 p++;
01754 }
01755 if (!*p) {
01756
01757 if (space) {
01758 *value = '\0';
01759 }
01760 return cgiFormNotFound;
01761 }
01762 p++;
01763
01764 while ((*p) && isspace(*p)) {
01765 p++;
01766 }
01767 }
01768 }
01769
01770
01771 if (space) {
01772 *value = '\0';
01773 }
01774 return cgiFormNotFound;
01775 }
01776
01777 cgiFormResultType cgiCookieInteger(
01778 char *name,
01779 int *result,
01780 int defaultV)
01781 {
01782 char buffer[256];
01783 cgiFormResultType r =
01784 cgiCookieString(name, buffer, sizeof(buffer));
01785 if (r != cgiFormSuccess) {
01786 *result = defaultV;
01787 } else {
01788 *result = atoi(buffer);
01789 }
01790 return r;
01791 }
01792
01793 void cgiHeaderCookieSetInteger(char *name, int value, int secondsToLive,
01794 char *path, char *domain)
01795 {
01796 char svalue[256];
01797 sprintf(svalue, "%d", value);
01798 cgiHeaderCookieSetString(name, svalue, secondsToLive, path, domain);
01799 }
01800
01801 char *days[] = {
01802 "Sun",
01803 "Mon",
01804 "Tue",
01805 "Wed",
01806 "Thu",
01807 "Fri",
01808 "Sat"
01809 };
01810
01811 char *months[] = {
01812 "Jan",
01813 "Feb",
01814 "Mar",
01815 "Apr",
01816 "May",
01817 "Jun",
01818 "Jul",
01819 "Aug",
01820 "Sep",
01821 "Oct",
01822 "Nov",
01823 "Dec"
01824 };
01825
01826 void cgiHeaderCookieSetString(char *name, char *value, int secondsToLive,
01827 char *path, char *domain)
01828 {
01829
01830
01831
01832
01833
01834
01835
01836
01837
01838
01839 time_t now;
01840 time_t then;
01841 struct tm *gt;
01842 time(&now);
01843 then = now + secondsToLive;
01844 gt = gmtime(&then);
01845 fprintf(cgiOut,
01846 "Set-Cookie: %s=%s; domain=%s; expires=%s, %02d-%s-%04d %02d:%02d:%02d GMT; path=%s\r\n",
01847 name, value, domain,
01848 days[gt->tm_wday],
01849 gt->tm_mday,
01850 months[gt->tm_mon],
01851 gt->tm_year + 1900,
01852 gt->tm_hour,
01853 gt->tm_min,
01854 gt->tm_sec,
01855 path);
01856 }
01857
01858 void cgiHeaderLocation(char *redirectUrl) {
01859 fprintf(cgiOut, "Location: %s\r\n\r\n", redirectUrl);
01860 }
01861
01862 void cgiHeaderStatus(int status, char *statusMessage) {
01863 fprintf(cgiOut, "Status: %d %s\r\n\r\n", status, statusMessage);
01864 }
01865
01866 void cgiHeaderContentType(char *mimeType) {
01867 fprintf(cgiOut, "Content-type: %s\r\n\r\n", mimeType);
01868 }
01869
01870 static int cgiWriteString(FILE *out, char *s);
01871
01872 static int cgiWriteInt(FILE *out, int i);
01873
01874 #define CGIC_VERSION "2.0"
01875
01876 cgiEnvironmentResultType cgiWriteEnvironment(char *filename) {
01877 FILE *out;
01878 cgiFormEntry *e;
01879
01880 out = fopen(filename, "wb");
01881 if (!out) {
01882
01883 return cgiEnvironmentIO;
01884 }
01885 if (!cgiWriteString(out, "CGIC2.0")) {
01886 goto error;
01887 }
01888 if (!cgiWriteString(out, cgiServerSoftware)) {
01889 goto error;
01890 }
01891 if (!cgiWriteString(out, cgiServerName)) {
01892 goto error;
01893 }
01894 if (!cgiWriteString(out, cgiGatewayInterface)) {
01895 goto error;
01896 }
01897 if (!cgiWriteString(out, cgiServerProtocol)) {
01898 goto error;
01899 }
01900 if (!cgiWriteString(out, cgiServerPort)) {
01901 goto error;
01902 }
01903 if (!cgiWriteString(out, cgiRequestMethod)) {
01904 goto error;
01905 }
01906 if (!cgiWriteString(out, cgiPathInfo)) {
01907 goto error;
01908 }
01909 if (!cgiWriteString(out, cgiPathTranslated)) {
01910 goto error;
01911 }
01912 if (!cgiWriteString(out, cgiScriptName)) {
01913 goto error;
01914 }
01915 if (!cgiWriteString(out, cgiQueryString)) {
01916 goto error;
01917 }
01918 if (!cgiWriteString(out, cgiRemoteHost)) {
01919 goto error;
01920 }
01921 if (!cgiWriteString(out, cgiRemoteAddr)) {
01922 goto error;
01923 }
01924 if (!cgiWriteString(out, cgiAuthType)) {
01925 goto error;
01926 }
01927 if (!cgiWriteString(out, cgiRemoteUser)) {
01928 goto error;
01929 }
01930 if (!cgiWriteString(out, cgiRemoteIdent)) {
01931 goto error;
01932 }
01933 if (!cgiWriteString(out, cgiContentType)) {
01934 goto error;
01935 }
01936 if (!cgiWriteString(out, cgiAccept)) {
01937 goto error;
01938 }
01939 if (!cgiWriteString(out, cgiUserAgent)) {
01940 goto error;
01941 }
01942 if (!cgiWriteString(out, cgiReferrer)) {
01943 goto error;
01944 }
01945 if (!cgiWriteString(out, cgiCookie)) {
01946 goto error;
01947 }
01948 if (!cgiWriteInt(out, cgiContentLength)) {
01949 goto error;
01950 }
01951 e = cgiFormEntryFirst;
01952 while (e) {
01953 cgiFilePtr fp;
01954 if (!cgiWriteString(out, e->attr)) {
01955 goto error;
01956 }
01957 if (!cgiWriteString(out, e->value)) {
01958 goto error;
01959 }
01960
01961 if (!cgiWriteString(out, e->fileName)) {
01962 goto error;
01963 }
01964 if (!cgiWriteString(out, e->contentType)) {
01965 goto error;
01966 }
01967 if (!cgiWriteInt(out, e->valueLength)) {
01968 goto error;
01969 }
01970 if (cgiFormFileOpen(e->attr, &fp) == cgiFormSuccess) {
01971 char buffer[1024];
01972 int got;
01973 if (!cgiWriteInt(out, 1)) {
01974 cgiFormFileClose(fp);
01975 goto error;
01976 }
01977 while (cgiFormFileRead(fp, buffer,
01978 sizeof(buffer), &got) == cgiFormSuccess)
01979 {
01980 if (((int) fwrite(buffer, 1, got, out)) != got) {
01981 cgiFormFileClose(fp);
01982 goto error;
01983 }
01984 }
01985 if (cgiFormFileClose(fp) != cgiFormSuccess) {
01986 goto error;
01987 }
01988 } else {
01989 if (!cgiWriteInt(out, 0)) {
01990 goto error;
01991 }
01992 }
01993 e = e->next;
01994 }
01995 fclose(out);
01996 return cgiEnvironmentSuccess;
01997 error:
01998 fclose(out);
01999
02000
02001
02002 unlink(filename);
02003 return cgiEnvironmentIO;
02004 }
02005
02006 static int cgiWriteString(FILE *out, char *s) {
02007 int len = (int) strlen(s);
02008 cgiWriteInt(out, len);
02009 if (((int) fwrite(s, 1, len, out)) != len) {
02010 return 0;
02011 }
02012 return 1;
02013 }
02014
02015 static int cgiWriteInt(FILE *out, int i) {
02016 if (!fwrite(&i, sizeof(int), 1, out)) {
02017 return 0;
02018 }
02019 return 1;
02020 }
02021
02022 static int cgiReadString(FILE *out, char **s);
02023
02024 static int cgiReadInt(FILE *out, int *i);
02025
02026 cgiEnvironmentResultType cgiReadEnvironment(char *filename) {
02027 FILE *in;
02028 cgiFormEntry *e = 0, *p;
02029 char *version;
02030
02031 cgiEnvironmentResultType result = cgiEnvironmentIO;
02032
02033 cgiFreeResources();
02034
02035 in = fopen(filename, "rb");
02036 if (!in) {
02037
02038 return cgiEnvironmentIO;
02039 }
02040 if (!cgiReadString(in, &version)) {
02041 goto error;
02042 }
02043 if (strcmp(version, "CGIC" CGIC_VERSION)) {
02044
02045 free(version);
02046 return cgiEnvironmentWrongVersion;
02047 }
02048
02049 free(version);
02050 if (!cgiReadString(in, &cgiServerSoftware)) {
02051 goto error;
02052 }
02053 if (!cgiReadString(in, &cgiServerName)) {
02054 goto error;
02055 }
02056 if (!cgiReadString(in, &cgiGatewayInterface)) {
02057 goto error;
02058 }
02059 if (!cgiReadString(in, &cgiServerProtocol)) {
02060 goto error;
02061 }
02062 if (!cgiReadString(in, &cgiServerPort)) {
02063 goto error;
02064 }
02065 if (!cgiReadString(in, &cgiRequestMethod)) {
02066 goto error;
02067 }
02068 if (!cgiReadString(in, &cgiPathInfo)) {
02069 goto error;
02070 }
02071 if (!cgiReadString(in, &cgiPathTranslated)) {
02072 goto error;
02073 }
02074 if (!cgiReadString(in, &cgiScriptName)) {
02075 goto error;
02076 }
02077 if (!cgiReadString(in, &cgiQueryString)) {
02078 goto error;
02079 }
02080 if (!cgiReadString(in, &cgiRemoteHost)) {
02081 goto error;
02082 }
02083 if (!cgiReadString(in, &cgiRemoteAddr)) {
02084 goto error;
02085 }
02086 if (!cgiReadString(in, &cgiAuthType)) {
02087 goto error;
02088 }
02089 if (!cgiReadString(in, &cgiRemoteUser)) {
02090 goto error;
02091 }
02092 if (!cgiReadString(in, &cgiRemoteIdent)) {
02093 goto error;
02094 }
02095 if (!cgiReadString(in, &cgiContentType)) {
02096 goto error;
02097 }
02098 if (!cgiReadString(in, &cgiAccept)) {
02099 goto error;
02100 }
02101 if (!cgiReadString(in, &cgiUserAgent)) {
02102 goto error;
02103 }
02104 if (!cgiReadString(in, &cgiReferrer)) {
02105 goto error;
02106 }
02107
02108 if (!cgiReadString(in, &cgiCookie)) {
02109 goto error;
02110 }
02111 if (!cgiReadInt(in, &cgiContentLength)) {
02112 goto error;
02113 }
02114 p = 0;
02115 while (1) {
02116 int fileFlag;
02117 e = (cgiFormEntry *) calloc(1, sizeof(cgiFormEntry));
02118 if (!e) {
02119 cgiFreeResources();
02120 fclose(in);
02121 return cgiEnvironmentMemory;
02122 }
02123 memset(e, 0, sizeof(cgiFormEntry));
02124 if (!cgiReadString(in, &e->attr)) {
02125
02126
02127 free(e);
02128 break;
02129 }
02130 if (!cgiReadString(in, &e->value)) {
02131 goto outOfMemory;
02132 }
02133 if (!cgiReadString(in, &e->fileName)) {
02134 goto outOfMemory;
02135 }
02136 if (!cgiReadString(in, &e->contentType)) {
02137 goto outOfMemory;
02138 }
02139 if (!cgiReadInt(in, &e->valueLength)) {
02140 goto outOfMemory;
02141 }
02142 if (!cgiReadInt(in, &fileFlag)) {
02143 goto outOfMemory;
02144 }
02145 if (fileFlag) {
02146 char buffer[1024];
02147 FILE *out;
02148 char tfileName[1024];
02149 int got;
02150 int len = e->valueLength;
02151 if (getTempFileName(tfileName)
02152 != cgiParseSuccess)
02153 {
02154 result = cgiEnvironmentIO;
02155 goto error;
02156 }
02157 out = fopen(tfileName, "w+b");
02158 if (!out) {
02159 result = cgiEnvironmentIO;
02160 goto error;
02161 }
02162 while (len > 0) {
02163
02164
02165
02166 int tryr = len;
02167 if (tryr > ((int) sizeof(buffer))) {
02168 tryr = sizeof(buffer);
02169 }
02170 got = fread(buffer, 1, tryr, in);
02171 if (got <= 0) {
02172 result = cgiEnvironmentIO;
02173 fclose(out);
02174 unlink(tfileName);
02175 goto error;
02176 }
02177 if (((int) fwrite(buffer, 1, got, out)) != got) {
02178 result = cgiEnvironmentIO;
02179 fclose(out);
02180 unlink(tfileName);
02181 goto error;
02182 }
02183 len -= got;
02184 }
02185 fclose(out);
02186 e->tfileName = (char *) malloc((int) strlen(tfileName) + 1);
02187 if (!e->tfileName) {
02188 result = cgiEnvironmentMemory;
02189 unlink(tfileName);
02190 goto error;
02191 }
02192 strcpy(e->tfileName, tfileName);
02193 } else {
02194 e->tfileName = (char *) malloc(1);
02195 if (!e->tfileName) {
02196 result = cgiEnvironmentMemory;
02197 goto error;
02198 }
02199 }
02200 e->next = 0;
02201 if (p) {
02202 p->next = e;
02203 } else {
02204 cgiFormEntryFirst = e;
02205 }
02206 p = e;
02207 }
02208 fclose(in);
02209 cgiRestored = 1;
02210 return cgiEnvironmentSuccess;
02211 outOfMemory:
02212 result = cgiEnvironmentMemory;
02213 error:
02214 cgiFreeResources();
02215 fclose(in);
02216 if (e) {
02217 if (e->attr) {
02218 free(e->attr);
02219 }
02220 if (e->value) {
02221 free(e->value);
02222 }
02223 if (e->fileName) {
02224 free(e->fileName);
02225 }
02226 if (e->contentType) {
02227 free(e->contentType);
02228 }
02229 if (e->tfileName) {
02230 free(e->tfileName);
02231 }
02232 free(e);
02233 }
02234 return result;
02235 }
02236
02237 static int cgiReadString(FILE *in, char **s) {
02238 int len;
02239
02240 if (!cgiReadInt(in, &len)) {
02241 return 0;
02242 }
02243 *s = (char *) malloc(len + 1);
02244 if (!(*s)) {
02245 return 0;
02246 }
02247 if (((int) fread(*s, 1, len, in)) != len) {
02248 return 0;
02249 }
02250 (*s)[len] = '\0';
02251 return 1;
02252 }
02253
02254 static int cgiReadInt(FILE *out, int *i) {
02255 if (!fread(i, sizeof(int), 1, out)) {
02256 return 0;
02257 }
02258 return 1;
02259 }
02260
02261 static int cgiStrEqNc(char *s1, char *s2) {
02262 while(1) {
02263 if (!(*s1)) {
02264 if (!(*s2)) {
02265 return 1;
02266 } else {
02267 return 0;
02268 }
02269 } else if (!(*s2)) {
02270 return 0;
02271 }
02272 if (isalpha(*s1)) {
02273 if (tolower(*s1) != tolower(*s2)) {
02274 return 0;
02275 }
02276 } else if ((*s1) != (*s2)) {
02277 return 0;
02278 }
02279 s1++;
02280 s2++;
02281 }
02282 }
02283
02284 static int cgiStrBeginsNc(char *s1, char *s2) {
02285 while(1) {
02286 if (!(*s2)) {
02287 return 1;
02288 } else if (!(*s1)) {
02289 return 0;
02290 }
02291 if (isalpha(*s1)) {
02292 if (tolower(*s1) != tolower(*s2)) {
02293 return 0;
02294 }
02295 } else if ((*s1) != (*s2)) {
02296 return 0;
02297 }
02298 s1++;
02299 s2++;
02300 }
02301 }
02302
02303 static char *cgiFindTarget = 0;
02304 static cgiFormEntry *cgiFindPos = 0;
02305
02306 static cgiFormEntry *cgiFormEntryFindFirst(char *name) {
02307 cgiFindTarget = name;
02308 cgiFindPos = cgiFormEntryFirst;
02309 return cgiFormEntryFindNext();
02310 }
02311
02312 static cgiFormEntry *cgiFormEntryFindNext() {
02313 while (cgiFindPos) {
02314 cgiFormEntry *c = cgiFindPos;
02315 cgiFindPos = c->next;
02316 if (!strcmp(c -> attr, cgiFindTarget)) {
02317 return c;
02318 }
02319 }
02320 return 0;
02321 }
02322
02323 static int cgiFirstNonspaceChar(char *s) {
02324 int len = strspn(s, " \n\r\t");
02325 return s[len];
02326 }
02327
02328 void cgiStringArrayFree(char **stringArray) {
02329 char *p;
02330 char **arrayItself = stringArray;
02331 p = *stringArray;
02332 while (p) {
02333 free(p);
02334 stringArray++;
02335 p = *stringArray;
02336 }
02337
02338 free(arrayItself);
02339 }
02340
02341 cgiFormResultType cgiCookies(char ***result) {
02342 char **stringArray;
02343 int i;
02344 int total = 0;
02345 char *p;
02346 char *n;
02347 p = cgiCookie;
02348 while (*p) {
02349 if (*p == '=') {
02350 total++;
02351 }
02352 p++;
02353 }
02354 stringArray = (char **) malloc(sizeof(char *) * (total + 1));
02355 if (!stringArray) {
02356 *result = 0;
02357 return cgiFormMemory;
02358 }
02359
02360 for (i=0; (i <= total); i++) {
02361 stringArray[i] = 0;
02362 }
02363 i = 0;
02364 p = cgiCookie;
02365 while (*p) {
02366 while (*p && isspace(*p)) {
02367 p++;
02368 }
02369 n = p;
02370 while (*p && (*p != '=')) {
02371 p++;
02372 }
02373 if (p != n) {
02374 stringArray[i] = (char *) malloc((p - n) + 1);
02375 if (!stringArray[i]) {
02376 cgiStringArrayFree(stringArray);
02377 *result = 0;
02378 return cgiFormMemory;
02379 }
02380 memcpy(stringArray[i], n, p - n);
02381 stringArray[i][p - n] = '\0';
02382 i++;
02383 }
02384 while (*p && (*p != ';')) {
02385 p++;
02386 }
02387 if (!*p) {
02388 break;
02389 }
02390 if (*p == ';') {
02391 p++;
02392 }
02393 }
02394 *result = stringArray;
02395 return cgiFormSuccess;
02396 }
02397
02398 cgiFormResultType cgiFormEntries(char ***result) {
02399 char **stringArray;
02400 cgiFormEntry *e, *pe;
02401 int i;
02402 int total = 0;
02403 e = cgiFormEntryFirst;
02404 while (e) {
02405
02406
02407 pe = cgiFormEntryFirst;
02408 while (pe != e) {
02409 if (!strcmp(e->attr, pe->attr)) {
02410 goto skipSecondValue;
02411 }
02412 pe = pe->next;
02413 }
02414 total++;
02415 skipSecondValue:
02416 e = e->next;
02417 }
02418 stringArray = (char **) malloc(sizeof(char *) * (total + 1));
02419 if (!stringArray) {
02420 *result = 0;
02421 return cgiFormMemory;
02422 }
02423
02424 for (i=0; (i <= total); i++) {
02425 stringArray[i] = 0;
02426 }
02427
02428 e = cgiFormEntryFirst;
02429 i = 0;
02430 while (e) {
02431 int space;
02432
02433
02434 pe = cgiFormEntryFirst;
02435 while (pe != e) {
02436 if (!strcmp(e->attr, pe->attr)) {
02437 goto skipSecondValue2;
02438 }
02439 pe = pe->next;
02440 }
02441 space = (int) strlen(e->attr) + 1;
02442 stringArray[i] = (char *) malloc(space);
02443 if (stringArray[i] == 0) {
02444
02445 cgiStringArrayFree(stringArray);
02446 *result = 0;
02447 return cgiFormMemory;
02448 }
02449 strcpy(stringArray[i], e->attr);
02450 i++;
02451 skipSecondValue2:
02452 e = e->next;
02453 }
02454 *result = stringArray;
02455 return cgiFormSuccess;
02456 }
02457
02458 #define TRYPUTC(ch) \
02459 { \
02460 if (putc((ch), cgiOut) == EOF) { \
02461 return cgiFormIO; \
02462 } \
02463 }
02464
02465 cgiFormResultType cgiHtmlEscapeData(char *data, int len)
02466 {
02467 while (len--) {
02468 if (*data == '<') {
02469 TRYPUTC('&');
02470 TRYPUTC('l');
02471 TRYPUTC('t');
02472 TRYPUTC(';');
02473 } else if (*data == '&') {
02474 TRYPUTC('&');
02475 TRYPUTC('a');
02476 TRYPUTC('m');
02477 TRYPUTC('p');
02478 TRYPUTC(';');
02479 } else if (*data == '>') {
02480 TRYPUTC('&');
02481 TRYPUTC('g');
02482 TRYPUTC('t');
02483 TRYPUTC(';');
02484 } else {
02485 TRYPUTC(*data);
02486 }
02487 data++;
02488 }
02489 return cgiFormSuccess;
02490 }
02491
02492 cgiFormResultType cgiHtmlEscape(char *s)
02493 {
02494 return cgiHtmlEscapeData(s, (int) strlen(s));
02495 }
02496
02497
02498
02499
02500
02501
02502
02503 cgiFormResultType cgiValueEscapeData(char *data, int len)
02504 {
02505 while (len--) {
02506 if (*data == '\"') {
02507 TRYPUTC('&');
02508 TRYPUTC('#');
02509 TRYPUTC('3');
02510 TRYPUTC('4');
02511 TRYPUTC(';');
02512 } else {
02513 TRYPUTC(*data);
02514 }
02515 data++;
02516 }
02517 return cgiFormSuccess;
02518 }
02519
02520 cgiFormResultType cgiValueEscape(char *s)
02521 {
02522 return cgiValueEscapeData(s, (int) strlen(s));
02523 }
02524
02525