home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / CGI.ZIP / cgiportal.cpp next >
Encoding:
C/C++ Source or Header  |  1999-02-23  |  18.7 KB  |  532 lines

  1. #include "cgiportal.h"
  2.  
  3. /*************************************************************************
  4.  
  5. CGIPortal is copyright 1999 Lextek International
  6. All Rights Reserved.
  7.  
  8. Lextek International specializes in high performance full text indexing
  9. and retrieval software ("search engines").  These search engines are
  10. programmed in C/C++ and are not simply another Perl application but
  11. are highly optomized utilizing the latest research and technology
  12. in information retrieval.  Please e-mail pollarda@lextek.com
  13. if you have need of a full text indexing and retrieval engine to add
  14. search engine functionality to your web application.
  15.  
  16. This application was written for Lextek International by Art Pollard
  17.  
  18. Permission is granted to you to use this code module in your web
  19. application(s) free of charge.  No warrenty is made as to the suitability
  20. of CGIPortal to your application or even that CGIPortal is bug or error free.
  21.  
  22. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
  23. WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
  24. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
  25. OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
  26. KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
  27. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  28. PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
  29. LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
  30. THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
  31.  
  32. *************************************************************************/
  33.  
  34.  
  35.  
  36. /*****************************************************************
  37. ByteToHex() converts the character Ch to a hexidecimal value.  The
  38. buffer where the hex value is placed is specified by Hex.  It is
  39. important to note that the buffer specified by Hex must be at
  40. least 2 bytes in length as that is how large the hex value which
  41. will be placed in Hex is going to be.
  42. *****************************************************************/
  43.  
  44.  
  45. void ByteToHex(char *Hex, char Ch) {
  46.     char HexCodes[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  47.  
  48.    Hex[0] = HexCodes[(Ch >> 4) & 0x0F];
  49.    Hex[1] = HexCodes[Ch & 0x0F];
  50. }
  51.  
  52.  
  53. /*****************************************************************
  54. HexToByte converts the two character hex code specified by Hex into
  55. a character and places it at the position specified by Byte.
  56. *****************************************************************/
  57.  
  58. void HexToByte(char *Byte, char *Hex) {
  59.     size_t Counter;
  60.     for(Counter = 0; Counter < 2; Counter ++) {
  61.        *Byte <<= 4;
  62.  
  63.         if(Hex[Counter] >= '0' && Hex[Counter] <= '9')
  64.             *Byte |= (0x0F & (Hex[Counter] - '0'));
  65.       else
  66.       if(Hex[Counter] >= 'a' && Hex[Counter] <= 'f')
  67.             *Byte |= (0x0F & ((Hex[Counter] - 'a') + 0x0A));
  68.       else
  69.       if(Hex[Counter] >= 'A' && Hex[Counter] <= 'F')
  70.             *Byte |= (0x0F & ((Hex[Counter] - 'A') + 0x0A));
  71.    }
  72. }
  73.  
  74. /*****************************************************************
  75. UnescapeURLData is a utility function (not used by CGIPortal) which
  76. is provided mainly for your benifit.  This function converts any
  77. hex codes to their appropriate characters, and any other URL
  78. specific characters to their appropriate characters (e.g. '+' -> ' ').
  79. Since an unescaped string is shorter than the escaped string, this is
  80. all done in place.
  81. *****************************************************************/
  82.  
  83. void UnescapeURLData(char *String) {
  84.     size_t Counter;
  85.    size_t OutputPos;
  86.  
  87.    for(Counter = 0, OutputPos = 0; String[Counter] != 0;) {
  88.        if(String[Counter] == '+') {
  89.           String[OutputPos] = ' ';
  90.          OutputPos ++;
  91.          Counter += 3;
  92.          continue;
  93.       }
  94.       if(String[Counter] == '%') {
  95.           HexToByte(&String[OutputPos],&String[Counter + 1]);
  96.          OutputPos ++;
  97.          Counter += 3;
  98.          continue;
  99.       }
  100.       String[OutputPos] = String[Counter];
  101.       Counter ++; OutputPos ++;
  102.    }
  103.    String[OutputPos] = 0x00;
  104. }
  105.  
  106. /*****************************************************************
  107. AddPointerToPointerList() is a CGIPortal utility function which
  108. is used interally to add a pointer to the pointer list expanding
  109. the list buffer if need be.  This function returns 0 if not enough
  110. memory is available or 1 on success.
  111. *****************************************************************/
  112.  
  113.  
  114. int AddPointerToPointerList(CGIVarListT *CGIVars, char *Pointer) {
  115.     char **PointerList,**Tmp;
  116.    size_t NumAllocatedPointers;
  117.  
  118.     if(CGIVars->NumValuePointers == CGIVars->ValuePointerListSize) {
  119.  
  120.        if(CGIVars->NumValuePointers < 32)
  121.           NumAllocatedPointers = 32;
  122.       else
  123.           NumAllocatedPointers <<= 1;
  124.  
  125.        PointerList = (char **) malloc(NumAllocatedPointers * sizeof(char *));
  126.  
  127.       if(PointerList == NULL)
  128.           return 0;
  129.  
  130.       memcpy(PointerList,&CGIVars->NumValuePointers,CGIVars->NumValuePointers * sizeof(char *));
  131.       Tmp = CGIVars->ValuePointers;
  132.       CGIVars->ValuePointers = PointerList;
  133.  
  134.       CGIVars->ValuePointerListSize = NumAllocatedPointers;
  135.       free(Tmp);
  136.    }
  137.    CGIVars->ValuePointers[CGIVars->NumValuePointers] = Pointer;
  138.    CGIVars->NumValuePointers ++;
  139.    return 1;
  140. }
  141.  
  142. /*****************************************************************
  143. UnescapeURLDataAndDoPointers() is an internal function for CGI portal
  144. which unescapes the data passed into the CGI application and parses
  145. out all of the variables and their associated values.  This is done
  146. in one pass for speed reasons.  This function returns 0 on failure
  147. (you are out of memory and are probably running a Windows machine)
  148. or 1 on success.
  149. *****************************************************************/
  150.  
  151.  
  152. int UnescapeURLDataAndDoPointers(CGIVarListT *CGIVars) {
  153.     size_t     Counter;
  154.    size_t     OutputPos;
  155.    size_t     PointerCounter;
  156.    int      SetPointerFlag = 1;
  157.  
  158.    for(Counter = 0, OutputPos = 0; CGIVars->ValueList[Counter] != 0;) {
  159.        if(CGIVars->ValueList[Counter] == '&') {
  160.              CGIVars->ValueList[OutputPos] = 0x00;
  161.           SetPointerFlag = 1;
  162.          OutputPos ++;
  163.          Counter ++;
  164.          continue;
  165.       }
  166.  
  167.       if(SetPointerFlag == 1) {
  168.           if(AddPointerToPointerList(CGIVars,&CGIVars->ValueList[OutputPos]) == 0)
  169.               return 0;
  170.          SetPointerFlag = 0;
  171.       }
  172.  
  173.        if(CGIVars->ValueList[Counter] == '+') {
  174.           CGIVars->ValueList[OutputPos] = ' ';
  175.          OutputPos ++;
  176.          Counter += 3;
  177.       }
  178.       else
  179.       if(CGIVars->ValueList[Counter] == '%') {
  180.           HexToByte(&CGIVars->ValueList[OutputPos],&CGIVars->ValueList[Counter + 1]);
  181.          OutputPos ++;
  182.          Counter += 3;
  183.       }
  184.       else {
  185.           CGIVars->ValueList[OutputPos] = CGIVars->ValueList[Counter];
  186.           Counter ++; OutputPos ++;
  187.       }
  188.    }
  189.    CGIVars->ValueList[OutputPos] = 0x00;
  190.    return 1;
  191. }
  192.  
  193. /**************************************************************************
  194. ExpandVarListSize() is an internal function which is called if the
  195. variable list size is not large enough to hold all the variables available.
  196. This functions allocates a new buffer and all the variables are copied over
  197. and the old buffer replaced and freed.  This function returns 0 on failure
  198. and 1 on success.
  199. **************************************************************************/
  200.  
  201. int ExpandVarListSize(CGIVarListT *CGIVars, size_t Size) {
  202.     char *Temp;
  203.  
  204.    Temp = (char *) malloc(Size);
  205.    if(Temp == NULL)
  206.        return 0;
  207.    if(CGIVars->ValueList != NULL) {
  208.        memcpy(Temp,CGIVars->ValueList,CGIVars->AmountInList);
  209.        free(CGIVars->ValueList);
  210.    }
  211.    CGIVars->ValueList = Temp;
  212.     CGIVars->ValueListSize = Size;
  213.    return 1;
  214. }
  215. /**************************************************************************
  216. ReadStandardVariablesFromStdin() is an internal function used to
  217. read the CGI variables from standard in.  This function returns 0 on
  218. failure and 1 on success.  If a failure occurs, it means that you are
  219. out of memory.  (And thus must be running on a Windows machine.)
  220. **************************************************************************/
  221.  
  222. int ReadStandardVariablesFromStdin(CGIVarListT *CGIVars) {
  223.     char         *CurrentPos = CGIVars->ValueList + CGIVars->AmountInList, *Temp;
  224.    size_t   AmountRead, TotalRead = 0;
  225.  
  226.  
  227.     for(;;) {
  228.         AmountRead = fread(CurrentPos,1,CGIVars->ValueListSize - TotalRead,stdin);
  229.       if(AmountRead + TotalRead < CGIVars->ValueListSize) {
  230.           CGIVars->AmountInList += AmountRead;
  231.           CGIVars->ValueList[CGIVars->AmountInList] = 0x00;
  232.          break;
  233.       }
  234.       TotalRead += AmountRead;
  235.  
  236.       if(ExpandVarListSize(CGIVars, CGIVars->ValueListSize * 2) == 0)
  237.           return 0;
  238.    }
  239.    return 1;
  240. }
  241. /**************************************************************************
  242. ReadStandardVariablesFromEnvironment() is used internally to read the CGI
  243. data from the various environment variables.  The variables are passed
  244. in as the string EnvironmentVars.  This function returns 0 on
  245. failure and 1 on success.  If a failure occurs, it means that you are
  246. out of memory.  (And thus must be running on a Windows machine.)
  247. **************************************************************************/
  248. int ReadStandardVariablesFromEnvironment(CGIVarListT *CGIVars, char *EnvironmentVars) {
  249.     size_t    Length;
  250.  
  251.    Length =    strlen(EnvironmentVars);
  252.  
  253.    if(Length + 5 + CGIVars->AmountInList > CGIVars->ValueListSize) {
  254.        if(ExpandVarListSize(CGIVars,(CGIVars->ValueListSize + Length) * 2) == 0)
  255.           return 0;
  256.    }
  257.    strcpy(CGIVars->ValueList + CGIVars->AmountInList,"&");
  258.    CGIVars->AmountInList += 1;
  259.    strcpy(CGIVars->ValueList + CGIVars->AmountInList,EnvironmentVars);
  260.    CGIVars->AmountInList += Length;
  261.    return 1;
  262.  
  263. }
  264.  
  265. /**************************************************************************
  266. InitializeCGIVars() is used to initialize a CGIVarListT struct which has
  267. not been previously initilized.  (Or one that has been previously initilized
  268. but its memory has been freed by a call to ClearCGIVars().)  Be sure to
  269. call this function at the beginning of your CGI application to allocate
  270. the memory which is going to be used to read the CGI variables.
  271. The ListSize variable is the number of bytes which will be used initially
  272. to store the CGI variables. (A good starting off point is 1024)  The number
  273. of pointers is the size of the pointer list which will be used to point
  274. to each of the CGI variables.  The number of pointers should be as large if
  275. not larger than the maximum number of pointers used by your application.
  276.  
  277. Note:  Both the variable buffer and the pointer buffer will grow as need
  278. be as the CGI variables are read.  This means that ListSize and NumPointers
  279. does not need to be exact but absolutely must be bigger than 0.
  280.  
  281. This function returns 0 on failure (out of memory) and 1 on success.
  282.  
  283. **************************************************************************/
  284.  
  285. int InititalizeCGIVars(CGIVarListT *CGIVars, size_t ListSize, size_t NumPointers) {
  286.     CGIVars->ValueList = (char *) malloc(ListSize);
  287.    if(CGIVars->ValueList == NULL)
  288.        return 0;
  289.    CGIVars->ValueListSize = ListSize;
  290.    CGIVars->AmountInList = 0;
  291.  
  292.    CGIVars->ValuePointers = (char **) malloc(sizeof(char *) * NumPointers);
  293.    if(CGIVars->ValuePointers == NULL) {
  294.        free(CGIVars->ValueList);
  295.       return 0;
  296.    }
  297.    CGIVars->ValuePointerListSize = NumPointers;
  298.    CGIVars->NumValuePointers = 0;
  299.    //CGIVars->CookieList = NULL;
  300. }
  301.  
  302. /**************************************************************************
  303. ResetCGIVars() resets te CGIVarListT structure.  This does not initilize
  304. it but serves as a way for you to reuse the CGIVarList struct without having
  305. to free and reallocate memory every time you want to use the structure.
  306. This function is aimed at long running CGI applications where more than
  307. one read of CGI variables (from stdin or the environment) is called for.
  308. **************************************************************************/
  309.  
  310. void ResetCGIVars(CGIVarListT *CGIVars) {
  311.     CGIVars->AmountInList         = 0;
  312.     CGIVars->NumValuePointers     = 0;
  313. }
  314.  
  315. /**************************************************************************
  316. ClearCGIVars() frees any memory allocated during InitializeCGIVars() or
  317. during the process of reading the CGI data.  Call this function at the
  318. end of your CGI program.
  319. **************************************************************************/
  320. void ClearCGIVars(CGIVarListT *CGIVars) {
  321.     if(CGIVars->ValueList != NULL)
  322.        free(CGIVars->ValueList);
  323.    if(CGIVars->ValuePointers != NULL)
  324.        free(CGIVars->ValuePointers);
  325. }
  326.  
  327. /**************************************************************************
  328. ReadCGIData() reads all of the variables available when the CGI application
  329. is called.  It also unescapes any data stored in the variable names/data
  330. and stores it all in a list of 0x00 delimited strings.  (This of course
  331. means that you can't have 0x00 (%00) in your data.)  Call this function
  332. when you want to begin reading the variable names from the environment
  333. or standard input.  This function returns 0 on
  334. failure and 1 on success.  If a failure occurs, it means that you are
  335. out of memory.  (And thus must be running on a Windows machine.)
  336. **************************************************************************/
  337.  
  338. int ReadCGIData(CGIVarListT *CGIVars) {
  339.        char *Temp;
  340.  
  341.       CGIVars->AmountInList = 0;
  342.  
  343.       // If there is a POST method, go ahead and get it.
  344.       CGIVars->RequestMethod = getenv("REQUEST_METHOD");
  345.       if(CGIVars->RequestMethod != NULL && stricmp(CGIVars->RequestMethod,"POST")) {
  346.           if(ReadStandardVariablesFromStdin(CGIVars) == 0)
  347.              return 0;
  348.       }
  349.  
  350.       // If there is any GET method data then we get it too.
  351.       CGIVars->QueryString = getenv("QUERY_STRING");
  352.       if(CGIVars->QueryString != NULL) {
  353.           if(ReadStandardVariablesFromEnvironment(CGIVars,CGIVars->QueryString) == 0)
  354.              return 0;
  355.       }
  356.  
  357.       // If there is any Cookie info, we get that.
  358.       CGIVars->CookieString = getenv("HTTP_COOKIE");
  359.       if(CGIVars->CookieString != NULL) {
  360.           if(ReadStandardVariablesFromEnvironment(CGIVars,CGIVars->CookieString) == 0)
  361.              return 0;
  362.       }
  363.  
  364.       // Now we unescape the strings and set the pointers to the
  365.       // different values
  366.       UnescapeURLDataAndDoPointers(CGIVars);
  367.       return 1;
  368. }
  369. /***********************************************************************
  370. FindCGIValue() is used to find the value assocaiated with a given variable
  371. name.  FindCGIValue takes a pointer to a CGIVarListT struct (properly
  372. initialized of course) and a pointer to a 0x00 terminated string
  373. which specifies the variable name.  Note: Name matching is done
  374. CASE INSENSITIVE!!!  This function returns a pointer to the value
  375. if the variable name is found or NULL on failure.
  376. ***********************************************************************/
  377.  
  378. char *FindCGIValue(CGIVarListT *CGIVars, char *VariableName) {
  379.     char    ScratchBuff[80];
  380.     size_t     VariableNameLength;
  381.  
  382.    strcpy(ScratchBuff,VariableName);
  383.    strcat(ScratchBuff,"=");
  384.    VariableNameLength = strlen(ScratchBuff);
  385.    for(CGIVars->CurrentPos = 0; CGIVars->CurrentPos < CGIVars->NumValuePointers ; CGIVars->CurrentPos ++) {
  386.        if(strnicmp(CGIVars->ValuePointers[CGIVars->CurrentPos],ScratchBuff,VariableNameLength) == 0) {
  387.           return CGIVars->ValuePointers[CGIVars->CurrentPos] + VariableNameLength;
  388.       }
  389.    }
  390.    return NULL;
  391. }
  392.  
  393. /*********************************************************************
  394.  FindNextCGIValue() starts examining variables beginning at the first
  395. variable after the last one examined by either FindCGIValue() or
  396. FindNextCGIValue().  It takes as a paramerer the CGIVarList structure
  397. (properly initilized me of course) and a pointer to the 0x00 terminated
  398. variable name.  This returns either a pointer to the appropriate value
  399. if the value being looked for is found or NULL on failure.   Note: Name
  400. matching is done CASE INSENSITIVE!!!
  401. *********************************************************************/
  402.  
  403. char *FindNextCGIValue(CGIVarListT *CGIVars, char *VariableName) {
  404.     char    ScratchBuff[80];
  405.     size_t     VariableNameLength;
  406.  
  407.    strcpy(ScratchBuff,VariableName);
  408.    strcat(ScratchBuff,"=");
  409.    VariableNameLength = strlen(ScratchBuff);
  410.  
  411.    // Advance away from the last variable examined.
  412.    if(CGIVars->CurrentPos + 1 < CGIVars->NumValuePointers)
  413.        CGIVars->CurrentPos ++;
  414.  
  415.    for(; CGIVars->CurrentPos < CGIVars->NumValuePointers ; CGIVars->CurrentPos ++) {
  416.        if(strnicmp(CGIVars->ValuePointers[CGIVars->CurrentPos],ScratchBuff,VariableNameLength) == 0) {
  417.           return CGIVars->ValuePointers[CGIVars->CurrentPos] + VariableNameLength;
  418.       }
  419.    }
  420.    return NULL;
  421. }
  422.  
  423.  
  424. /*
  425.  
  426. Here is some pseudocode has to how the various
  427. functions may be called.
  428.  
  429.  
  430. // Standard CGI application
  431. int main() {
  432.     CGIVarListT Vars;
  433.    char *VariableValue;
  434.  
  435.    if(InititalizeCGIVars(&Vars,1024,12) == 0) {
  436.        // Out of memory
  437.    }
  438.       if(ReadCGIData(&Vars) == 0) {
  439.        // Out of memory
  440.    }
  441.    for (EachVariableYouWantToUse) {
  442.        VariableValue = FindCGIValue(&Vars,"MyVariable");
  443.       if(VariableValue == NULL) {
  444.           // Variable Not Found.
  445.       }
  446.    }
  447.    // Do your CGI stuff here.
  448.  
  449.  
  450.     ClearCGIVars(&Vars);
  451.    return 1;
  452. }
  453.  
  454.  
  455. Long Running  CGI application
  456.  
  457.  
  458. int main() {
  459.     CGIVarListT Vars;
  460.    char *VariableValue;
  461.  
  462.    if(InititalizeCGIVars(&Vars,1024,12) == 0) {
  463.        // Out of memory
  464.    }
  465.  
  466.    for(EachProcess) {
  467.       if(ReadCGIData(&Vars) == 0) {
  468.          // Out of memory
  469.       }
  470.       for (EachVariableYouWantToUse) {
  471.          VariableValue = FindCGIValue(&Vars,"MyVariable");
  472.          if(VariableValue == NULL) {
  473.             // Variable Not Found.
  474.          }
  475.       }
  476.  
  477.       // Do your CGI stuff here.
  478.  
  479.       ResetCGIVars(&Vars);
  480.    }
  481.  
  482.     ClearCGIVars(&Vars);
  483.    return 1;
  484. }
  485.  
  486.  
  487. */
  488.  
  489.  
  490.  
  491.  
  492. /*
  493. Simple test program which grabs the CGI data from the environment
  494. variables QUERY_STRING and HTTP_COOKIE.
  495.  
  496. int main() {
  497.     char     Choice[80], *VariableValue;
  498.    int    Result;
  499.    CGIVarListT Vars;
  500.  
  501.    putenv("QUERY_STRING=Jane=Doe%20a%20Deer&Dinkum=Software&Hewlett=Packard");
  502.    putenv("HTTP_COOKIE=John=1&Mary=2&Henry=3&Joe=4");
  503.  
  504.    for(;;) {
  505.        printf("\n\n1)  Parse Header");
  506.       printf("\n2)  Get Value");
  507.       printf("\n0)  Quit\n:");
  508.       gets(Choice);
  509.       Result = atoi(Choice);
  510.       switch(Result) {
  511.           case 1:    InititalizeCGIVars(&Vars,1024,12);
  512.                     ReadCGIData(&Vars);
  513.                     break;
  514.          case 2:     printf("\nVariable Name :");
  515.                      gets(Choice);
  516.                   VariableValue = FindCGIValue(&Vars,Choice);
  517.                         if(VariableValue != NULL)
  518.                       printf("Value = %s",VariableValue);
  519.                   else
  520.                       printf("Value = NULL");
  521.                      break;
  522.          case 0: exit(1);
  523.       };
  524.    }
  525. }
  526.  
  527.  
  528. */
  529.  
  530.  
  531.  
  532.