G:/ScriptBasic/source/extensions/cgi/cgi.c

Go to the documentation of this file.
00001 /*
00002 FILE: cgi.c
00003 HEADER: cgi.h
00004 
00005 Version: 2.0
00006 
00007 This code can be used to hadle web communication between
00008 the server and the application. Using the functions provided
00009 in this file you can write code runs with CGI as well as ISAPI.
00010 
00011 This code was developed to be used in the ScriptBasic project, but
00012 this code can be used as a stand-alone product embedded into other
00013 programs. This is GNU GPL protected.
00014 
00015 TO_HEADER:
00016 
00017 typedef struct _SymbolList {
00018   char *symbol;
00019   FILE *fp;   // pointer to the temporary file
00020   char *file; // in case this is an uploaded file name
00021   char *value;
00022   long len;   // length of the value or the saved temporary file
00023   struct _SymbolList *pHeaders; // in case of multipart
00024   struct _SymbolList *next;
00025   } SymbolList, *pSymbolList;
00026 
00027 typedef struct _DebugStore {
00028   char *ServerSoftware;
00029   char *ServerName;
00030   char *GatewayInterface;
00031   char *ServerProtocol;
00032   char *ServerPort;
00033   char *RequestMethod;
00034   char *PathInfo;
00035   char *PathTranslated;
00036   char *ScriptName;
00037   char *QueryString;
00038   char *RemoteHost;
00039   char *RemoteAddress;
00040   char *AuthType;
00041   char *RemoteUser;
00042   char *RemoteIdent;
00043   char *ContentType;
00044   char *ContentLength;
00045   char *UserAgent;
00046   char *Cookie;
00047 
00048   FILE *fpDebugInput;
00049   } DebugStore, *pDebugStore;
00050 
00051 typedef struct _CgiObject {
00052   void *(*maf)(long size, void *pSegment);
00053   void (*mrf)(void *MemoryToFree, void *pSegment);
00054   void *pSegment;
00055 
00056 #define CGI_INTERFACE_CGI   0x00000000 // this is the only implemented so far
00057 #define CGI_INTERFACE_ISAPI 0x00000001
00058 #define CGI_INTERFACE_NSAPI 0x00000002
00059 #define CGI_INTERFACE_FCGI  0x00000003
00060 #define CGI_INTERFACE_DEBUG 0x00000004 // read all information from a debug file
00061   long fInterface;   // constant defining the interface type
00062 
00063 #ifdef WIN32
00064   LPEXTENSION_CONTROL_BLOCK lpECB;
00065   char *pszNextChar;
00066   char *pszLocalBuffer;
00067   DWORD cbAvailable;
00068   DWORD dwIsapiBufferSize;
00069 #else
00070 #define LPEXTENSION_CONTROL_BLOCK void *
00071 #endif
00072 
00073   void *pEmbed; // embedder pointer for caller defined stdin/stdout and env functions
00074   int (*pfStdIn)(void *); // user defined stdin function gets pEmbed as argument
00075   void (*pfStdOut)(int, void*); // user defined stdout function gets pEmbed as second argument
00076   char *(*pfEnv)(void *,char *,long); //user defined environment function
00077 
00078   char *pszDebugFile; // the debug file if fInterface is CGI_INTERFACE_DEBUG, otherwise ignored
00079   pDebugStore pDebugInfo; // points to the allocated struct that stores CGI info read from the debug file
00080 
00081   char *pszBoundary; // multipart boundary string
00082   unsigned long cbBoundary;   // length of the boundary
00083   unsigned char *pszBuffer;   // buffer to store characters
00084   unsigned long cbBuffer;     // the actual size of the buffer
00085   unsigned long cbFill;       // the number of characters stored in the buffer at the moment
00086   unsigned long lBufferPosition; // the current buffer position when returning characters
00087   int (*CharacterInput)(struct _CgiObject *p);
00088   void *pInputParameter; // the parameter the input function can use
00089   unsigned long lContentLength;  // the length of the POST param (used by the CharacterInput function)
00090 
00091   pSymbolList pGetParameters; // point to GET parameters
00092   pSymbolList pPostParameters; // point to POST parameters
00093 
00094   unsigned long lBufferIncrease; // increase the buffer using this increment when buffer is small
00095   unsigned long lBufferMax;      // never exceed this size with the buffer
00096   unsigned long lContentMax;     // maximal content-length we deal with
00097   unsigned long lFileMax;        // maximal file length we deal with
00098 
00099 #define CGI_METHOD_NONE 0x00000000
00100 #define CGI_METHOD_GET  0x00000001
00101 #define CGI_METHOD_POST 0x00000002
00102 #define CGI_METHOD_UPL  0x00000004 // upload "method" this is a post method,
00103                                    //but here we treat it if it was a separate method
00104 // these methods are not implemented yet
00105 #define CGI_METHOD_PUT  0x00000008
00106 #define CGI_METHOD_DEL  0x00000010 
00107 #define CGI_METHOD_COPY 0x00000020
00108 #define CGI_METHOD_MOVE 0x00000040
00109 #define CGI_METHOD_HEAD 0x00000080
00110 
00111   long fMethods;        // allowed methods, each bit set is an allowed method
00112   } CgiObject, *pCgiObject;
00113 
00114 
00115 #define CGI_ERROR_BUFFER_OVERFLOW 0x00080001
00116 #define CGI_ERROR_BIG_CONTENT     0x00080002
00117 #define CGI_ERROR_INVALID_METHOD  0x00080003
00118 #define CGI_ERROR_NO_DEBUG_FILE   0x00080004
00119 #define CGI_ERROR_NOTIMP          0x00080005
00120 #define CGI_ERROR_EOF             0x00080006
00121 #define CGI_ERROR_ILLF_MULTI      0x00080007
00122 #define CGI_ERROR_FILEMAX         0x00080008
00123 #define CGI_ERROR_MEMORY_LOW      0x00080009
00124 #define CGI_ERROR_METHOD_NOTALL   0x0008000A
00125 #define CGI_ERROR_ILLF_MULTI1     0x00080017
00126 #define CGI_ERROR_ILLF_MULTI2     0x00080027
00127 #define CGI_ERROR_ILLF_MULTI3     0x00080037
00128 #define CGI_ERROR_ILLF_MULTI4     0x00080047
00129 #define CGI_ERROR_ILLF_MULTI5     0x00080057
00130 #define CGI_ERROR_ILLF_MULTI6     0x00080067
00131 #define CGI_ERROR_ILLF_MULTI7     0x00080077
00132 
00133 //this is a safe macro implementation of the functions
00134 #define cgi_EmptyBuffer(x) ((x)->cbFill=0)
00135 #define cgi_BufferFull(x)  ((x)->cbFill == (x)->cbBuffer)
00136 */
00137 #include <stdio.h>
00138 #include <stdlib.h>
00139 #include <memory.h>
00140 #include <ctype.h>
00141 #include <fcntl.h>
00142 #include <string.h>
00143 #include <ctype.h>
00144 #ifdef WIN32
00145 #include <io.h>
00146 #include <httpext.h>
00147 #endif
00148 
00149 #include "cgi.h"
00150 
00151 #define _getenv(X) (pCO->pfEnv ? pCO->pfEnv(pCO->pEmbed,(X),0) : getenv(X))
00152 
00153 #if (!defined(_WIN32) && !defined(__MACOS__))
00154 static int stricmp(char *a, char *b){
00155   char ca,cb;
00156 
00157   while( 1 ){
00158     ca = *a++;
00159     cb = *b++;
00160     ca = isupper(ca) ? tolower(ca) : ca;
00161     cb = isupper(cb) ? tolower(cb) : cb;
00162     if( ca == (char)0 && cb == (char)0 )return 0;
00163     if( ca != cb )return ca-cb;
00164     }
00165   }
00166 #endif
00167 
00168 
00169 #define CR '\r'
00170 #define LF '\n'
00171 /* initial buffer size */
00172 #define BUFFER_INCREASE 1024
00173 #define BUFFER_MAX      10240
00174 /* 10MB */
00175 #define CONTENT_MAX     0xA00000
00176 #define FILE_MAX        0xA00000
00177 /* 40KB */
00178 #define ISAPI_BUFFER    0xA000
00179 
00180 #define DEBUGFP (pCO->pDebugInfo->fpDebugInput)
00181 
00182 #define GETCHAR() (pCO->CharacterInput(pCO))
00183 #define ALLOC(x) (pCO->maf((x),pCO->pSegment))
00184 #define FREE(x)  (pCO->mrf((x),pCO->pSegment))
00185 
00186 static char x2c(char *what){
00187   register char digit;
00188 #define TOHEX(x)  ((x) >= 'A' ? (((x) & 0xdf) - 'A')+10 : ((x) - '0'))
00189 
00190   digit = TOHEX(*what);
00191   digit *= 16;
00192   what++;
00193   digit += TOHEX(*what);
00194   return digit;
00195 #undef TOHEX
00196 }
00197 
00198 static void unescape(char *s, long *len){
00199   char *p;
00200   long rest;
00201 
00202   p  = s;  
00203   rest = *len;
00204   while( rest ){
00205     if( *p == '+' )*p = ' ';
00206     p++;
00207     rest --;
00208     }
00209 
00210   p  = s;  
00211   rest = *len;
00212 
00213   while( rest ){
00214     *p = *s;
00215     if( *p == '%' ){
00216       s++;rest--;
00217       *p = x2c(s);
00218       s++;
00219       rest--;
00220       (*len) -= 2;
00221       }
00222     p++;
00223     s++;
00224     rest--;
00225     }
00226   }
00227 
00228 static void *my_maf(long size, void *p){
00229   return malloc(size);
00230   }
00231 static void my_mrf(void *q, void*p){
00232   free(q);
00233   }
00234 #ifdef WIN32
00235 static int IsapiGetChar(pCgiObject pCO){
00236   unsigned char ch; /* it IS important that this is unsigned otherwise a 255
00237                        would mean EOF */
00238 
00239   if( pCO->lContentLength == 0 )return EOF;
00240   if( pCO->cbAvailable ){
00241     pCO->cbAvailable--;
00242     ch = *(pCO->pszNextChar);
00243     pCO->lContentLength --;
00244     pCO->pszNextChar ++;
00245     return (unsigned int)ch;
00246     }
00247 
00248   if( pCO->pszLocalBuffer == NULL ){
00249     if( pCO->dwIsapiBufferSize > pCO->lContentLength )
00250       pCO->dwIsapiBufferSize = pCO->lContentLength;
00251     pCO->pszLocalBuffer = ALLOC(pCO->dwIsapiBufferSize);
00252     if( pCO->pszLocalBuffer == NULL )return EOF;
00253     }
00254   pCO->pszNextChar = pCO->pszLocalBuffer;
00255   pCO->cbAvailable = pCO->dwIsapiBufferSize;
00256   if( pCO->lpECB->ReadClient(pCO->lpECB->ConnID,pCO->pszLocalBuffer,&(pCO->cbAvailable)) && pCO->cbAvailable ){
00257     ch = *(pCO->pszNextChar);
00258     pCO->lContentLength --;
00259     pCO->cbAvailable--;
00260     pCO->pszNextChar ++;
00261     return (unsigned int)ch;
00262     }
00263   /* We will get here only if the client pressed the STOP button on the browser. */
00264   return EOF;
00265   }
00266 #endif
00267 static int CgiGetChar(pCgiObject pCO){
00268   int ch;
00269 #ifdef WIN32
00270   if( ! pCO->pfStdIn ){
00271     setmode(fileno(stdin), O_BINARY);   /* define stdin as binary */
00272     _fmode = O_BINARY;                    /* default all file I/O as binary */
00273      }
00274 #endif
00275   if( pCO->lContentLength ){
00276     pCO->lContentLength --;
00277     if( pCO->pfStdIn )
00278       ch = pCO->pfStdIn(pCO->pEmbed);
00279     else
00280       ch = getchar();
00281 
00282     return ch;
00283     }
00284   return EOF;
00285   }
00286 static void CgiPutChar(pCgiObject pCO, int ch){
00287   if( pCO->pfStdOut )
00288     pCO->pfStdOut(ch,pCO->pEmbed);
00289   else
00290     putc(ch,stdout);
00291   }
00292 static int DebugGetChar(pCgiObject pCO){
00293   int ch;
00294 #ifdef WIN32
00295   setmode(fileno(DEBUGFP), O_BINARY);   /* define stdin as binary */
00296   _fmode = O_BINARY;                    /* default all file I/O as binary */
00297 #endif
00298   ch = getc(DEBUGFP);
00299 
00300   return ch;
00301   }
00302 
00303 /*POD
00304 =H CGI handling
00305 
00306 This package contains functions that help you handle CGI (later NSAPI, ISAPI and FCGI)
00307 input in Web programs. The functions are written in a well defined manner, documented,
00308 thread aware.
00309 
00310 The functions to be used by external programs (the public functions) have abstract in this
00311 documentation. Other functions are listed and documented here, because they have to be
00312 documented for maintenance purposes. Some very small, almost inline functions are declared
00313 as static and are documented only in the source code.
00314 
00315 (zchar string means a string terminted by a character of code zero)
00316 
00317 Note that all function names are preceeded with the characters T<cgi_>
00318 
00319 Topics:
00320 
00321 CUT*/
00322 
00323 /*POD
00324 =section InitCgi
00325 =H Initialize a CgiObject with default values
00326 =abstract
00327 This function initializes a CgiObject filling the default values
00328 to handle the http request parameters via the CGI interface.
00329 =end
00330 
00331 This function initializes a CgiObject filling the default values
00332 to handle the http request parameters via the CGI interface.
00333 
00334 To handle CGI input the caller program should have a variable
00335 of type T<CgiObject>. This T<struct> variable will contain all
00336 information neccessary to handle the CGI input, and all functions
00337 request pointer to this variable as first argument. You can think
00338 of this T<struct> as the container for the class variables (except that
00339 this is written in C and not C++).
00340 
00341 T<mrf>
00342 
00343 T<maf>
00344 
00345 The memory handling functions are initialized to point to a function
00346 using T<malloc> and T<free>. You can change the fields T<maf> and T<mrf>
00347 to point to a T<m>emory T<a>llocation T<f>unction and to a T<m>emory
00348 T<r>eleasing T<f>unction that are similar to T<malloc> and T<free>, but
00349 also accept a second T<void *> argument. This T<void *> argument may help
00350 to use thread local allocation, or to use segmented allocation, where
00351 all memory chunks can be released with a single call using the T<void *>
00352 pointer. (See the http://www.emma.hu/scriptbasic application source and
00353 get the file T<myalloc.c> for example.)
00354 
00355 T<CharacterInput>
00356 
00357 The field T<CharacterInput> should point to a function that gets a pointer
00358 to the T<CgiObject> variable and returns an int, which is the next character
00359 or EOF in case no more input is available. This field is initialized to
00360 point to local function that reads the standard input (binary mode on Windows)
00361 but may be reseto to point to any other function in case you want to read a file
00362 for debugging purposes instead of the stdin.
00363 
00364 T<lBufferIncrease>
00365 
00366 The field T<lBufferIncrease> initialized to T<BUFFER_INCREASE>. (1KByte) This is the
00367 initial size of the buffer and this is the increase whenever the buffer seems to be
00368 small.
00369 
00370 T<lBufferMax>
00371 
00372 The fiels T<lBufferMax> is initialized to T<BUFFER_MAX>. (10KByte) This is the maximal
00373 size of the buffer. If the buffer needs to be larger than this size the program does
00374 not process the CGI input.
00375 
00376 The buffer should be large enough to handle POST data (but not uploaded files) and multipart
00377 headers (one at a time).
00378 
00379 T<lContentMax>
00380 
00381 The fiels T<lContentMax> is initialized to T<CONTENT_MAX>. (10MByte) This is the maximal size
00382 of the CGI input the program handles. Whenever the header field T<Content-Length> is
00383 larger than this size the program does not process the CGI input.
00384 
00385 T<lFileMax>
00386 
00387 The filed T<lFileMax> is initialized to T<FILE_MAX>. (10MByte) This is the maximal size
00388 of an uploaded file. Whenever a file is larger than this size the program does not process
00389 the CGI input.
00390 
00391 =hrule
00392 
00393 These parameters can be altered after calling this initialization function. These
00394 values help the program to minimize the effect of a denial of service attack sending
00395 huge amount of data to web scripts that do not expect to handle them.
00396 
00397 /*FUNCTION*/
00398 void cgi_InitCgi(pCgiObject pCO
00399   ){
00400 /*noverbatim
00401 CUT*/
00402   pCO->maf = my_maf;
00403   pCO->mrf = my_mrf;
00404   pCO->pSegment = NULL;
00405 
00406   pCO->fInterface = CGI_INTERFACE_CGI;
00407 
00408   pCO->pszBoundary = NULL;
00409   pCO->cbBoundary = 0;
00410   pCO->pszBuffer = NULL;
00411   pCO->cbBuffer = 0;
00412 
00413   pCO->cbFill = 0;
00414   pCO->lBufferPosition = 0;
00415 
00416   pCO->CharacterInput = CgiGetChar;
00417   pCO->pInputParameter = NULL;
00418   pCO->lContentLength = 0;
00419 
00420   pCO->lBufferIncrease = BUFFER_INCREASE;
00421   pCO->lBufferMax = BUFFER_MAX;
00422   pCO->pGetParameters = NULL;
00423   pCO->pPostParameters = NULL;
00424   pCO->lContentMax = CONTENT_MAX;
00425   pCO->lFileMax = FILE_MAX;
00426 #ifdef WIN32
00427   pCO->dwIsapiBufferSize = ISAPI_BUFFER;
00428 #endif
00429 
00430   pCO->fMethods = CGI_METHOD_GET | CGI_METHOD_POST | CGI_METHOD_UPL;
00431 
00432   pCO->pszDebugFile = NULL;
00433 
00434   pCO->pfStdIn = NULL;
00435   pCO->pfStdOut = NULL;
00436   pCO->pfEnv = NULL;
00437   pCO->pEmbed = NULL;
00438   }
00439 
00440 #ifdef WIN32
00441 /*POD
00442 =section InitIsapi
00443 =H Initialize a CgiObject with default values
00444 =abstract
00445 This function initializes a CgiObject filling the default values
00446 to handle the http request parameters via the ISAPI interface.
00447 =end
00448 
00449 This function initializes a CgiObject filling the default values
00450 to handle the http request parameters via the ISAPI interface.
00451 It actually does nothing else, but calls the CGI initialization function
00452 R<InitCgi> and then alters the field T<fInterface> of the CGI object
00453 to signal that this is an ISAPI interface handling case now.
00454 
00455 /*FUNCTION*/
00456 void cgi_InitIsapi(pCgiObject pCO,
00457                    LPEXTENSION_CONTROL_BLOCK lpECB
00458   ){
00459 /*noverbatim
00460 CUT*/
00461   cgi_InitCgi(pCO);
00462 
00463   pCO->lpECB = lpECB;
00464   pCO->CharacterInput = IsapiGetChar;
00465   pCO->pszNextChar = lpECB->lpbData;
00466   pCO->cbAvailable = lpECB->cbAvailable;
00467   pCO->fInterface = CGI_INTERFACE_ISAPI;
00468   pCO->pszLocalBuffer = NULL;
00469 
00470   pCO->pfStdIn = NULL;
00471   pCO->pfStdOut = NULL;
00472   pCO->pfEnv = NULL;
00473   pCO->pEmbed = NULL;
00474   }
00475 #else
00476 void cgi_InitIsapi(pCgiObject pCO,
00477                    LPEXTENSION_CONTROL_BLOCK lpECB
00478   ){
00479   /* on UNIX we do nothing */
00480   }
00481 #endif
00482 
00483 /*POD
00484 =section ReadHttpRequest
00485 =H Read the http request data
00486 =abstract
00487 This function reads the http request data and stores in linked lists available to query the
00488 values.
00489 =end
00490 
00491 The application program should call this function to process the CGI input data. The parameter
00492 T<pCO> should point to an initialized R<InitCgi> structure. The function decides what type of
00493 input handling is needed, reads the http request and stores them in the appropriate fields
00494 avaiable for later query.
00495 
00496 /*FUNCTION*/
00497 long cgi_ReadHttpRequest(pCgiObject pCO
00498   ){
00499 /*noverbatim
00500 CUT*/
00501   char LocalBuffer[1024],*s,*r;
00502   long w;
00503 
00504   switch( pCO->fInterface ){
00505     case CGI_INTERFACE_ISAPI:
00506       /* ISAPI methods need tamporary space to store the header
00507          variables. This is needed because the ISAPI interface does
00508          not return a pointer to a constant string but rather copies
00509          the value to a buffer that we have to provide. The pointers
00510          in the DebugStore are just fine for the purpose.            */
00511       pCO->pDebugInfo = ALLOC(sizeof(DebugStore));
00512       if( pCO->pDebugInfo == NULL )return CGI_ERROR_MEMORY_LOW;
00513       memset(pCO->pDebugInfo,0,sizeof(DebugStore));
00514     case CGI_INTERFACE_CGI:
00515     case CGI_INTERFACE_DEBUG:
00516 RetryWithDebugMode:
00517       if( NULL != (s = cgi_RequestMethod(pCO)) ){
00518         w = 0;
00519         if( !strcmp(s,"GET")  )w = CGI_METHOD_GET;
00520         else
00521         if( !strcmp(s,"HEAD") )w = CGI_METHOD_HEAD;
00522         if( w ){
00523           if( ! (pCO->fMethods&w) )return CGI_ERROR_METHOD_NOTALL;
00524           return cgi_GetGetParameters(pCO);
00525           }
00526         }
00527       if( s && !strcmp(s,"POST") ){
00528         if( ! (pCO->fMethods&CGI_METHOD_POST) )return CGI_ERROR_METHOD_NOTALL;
00529         r=cgi_ContentLength(pCO);
00530         pCO->lContentLength = r ? atol( r ) : 0 ;
00531         if( pCO->lContentLength > pCO->lContentMax )return CGI_ERROR_BIG_CONTENT;
00532         if( (r=cgi_ContentType(pCO)) && ! memcmp(r,"multipart/form-data",19) ){
00533           if( ! (pCO->fMethods&CGI_METHOD_UPL) )return CGI_ERROR_METHOD_NOTALL;
00534           return cgi_GetMultipartParameters(pCO);
00535           }
00536         else return cgi_GetPostParameters(pCO);
00537         }
00538      /* if it is already DEBUG then there is no way out */
00539      if( pCO->fInterface == CGI_INTERFACE_DEBUG )return CGI_ERROR_INVALID_METHOD;
00540      /* if this is neither GET nor POST then we try to switch to debug more */
00541      pCO->fInterface = CGI_INTERFACE_DEBUG;
00542 #define READL(x) if( fgets(LocalBuffer,1024,DEBUGFP) ){\
00543                  LocalBuffer[w=strlen(LocalBuffer)-2] = (char)0; /* remove terminating \r\n (we read binary)*/ \
00544                  pCO->pDebugInfo->x = ALLOC(w);\
00545                  if( pCO->pDebugInfo->x == NULL )return CGI_ERROR_MEMORY_LOW;\
00546                  strcpy(pCO->pDebugInfo->x,LocalBuffer);\
00547                  }else pCO->pDebugInfo->x = "";
00548 
00549       pCO->pDebugInfo = ALLOC(sizeof(DebugStore));
00550       if( pCO->pDebugInfo == NULL )return CGI_ERROR_MEMORY_LOW;
00551       if( pCO->pszDebugFile == NULL )return CGI_ERROR_NO_DEBUG_FILE;
00552       DEBUGFP = fopen(pCO->pszDebugFile,"rb");
00553       if( DEBUGFP == NULL )return CGI_ERROR_NO_DEBUG_FILE;
00554 
00555       READL(ServerSoftware);
00556       READL(ServerName);
00557       READL(GatewayInterface);
00558       READL(ServerProtocol);
00559       READL(ServerPort);
00560       READL(RequestMethod);
00561       READL(PathInfo);
00562       READL(PathTranslated);
00563       READL(ScriptName);
00564       READL(QueryString);
00565       READL(RemoteHost);
00566       READL(RemoteAddress);
00567       READL(AuthType);
00568       READL(RemoteUser);
00569       READL(RemoteIdent);
00570       READL(ContentType);
00571       READL(ContentLength);
00572       READL(UserAgent);
00573       READL(Cookie);
00574 
00575       pCO->CharacterInput = DebugGetChar;
00576       goto RetryWithDebugMode;
00577     case CGI_INTERFACE_NSAPI:
00578       return CGI_ERROR_NOTIMP;
00579     case CGI_INTERFACE_FCGI:
00580       return CGI_ERROR_NOTIMP;
00581     }
00582   return CGI_ERROR_INVALID_METHOD;
00583   }
00584 
00585 /*POD
00586 =section PostParam
00587 =H Query a POST parameter
00588 =abstract
00589 Use this function to get the value of a POST parameter
00590 =end
00591 
00592 The argument T<pszParam> should point to a zchar string
00593 containing the name of a POST parameter. The function returns
00594 the pointer to a constant string containing the value fo the parameter
00595 or NULL if there is no such parameter.
00596 
00597 /*FUNCTION*/
00598 char *cgi_PostParam(pCgiObject pCO,
00599                     char *pszParam
00600   ){
00601 /*noverbatim
00602 If there are more parameters with the same name only the first occurence is retrieved. Use the
00603 function R<PostParamEx> to iterate through all the parameters with a single name.
00604 CUT*/
00605   pSymbolList p;
00606 
00607   p = pCO->pPostParameters;
00608   while( p ){
00609     if( !strcmp(p->symbol,pszParam) )return p->value ? p->value : "";
00610     p = p->next;
00611     }
00612 
00613   return NULL;
00614   }
00615 
00616 /*POD
00617 =section GetParam
00618 =H Query a GET parameter
00619 =abstract
00620 Use this function to get the value of a GET parameter
00621 =end
00622 
00623 The argument T<pszParam> should point to a zchar string
00624 containing the name of a GET parameter. The function returns
00625 the pointer to a constant string containing the value fo the parameter
00626 or NULL if there is no such parameter.
00627 
00628 /*FUNCTION*/
00629 char *cgi_GetParam(pCgiObject pCO,
00630                    char *pszParam
00631   ){
00632 /*noverbatim
00633 If there are more parameters with the same name only the first occurence is retrieved. Use the
00634 function R<GetParamEx> to iterate through all the parameters with a single name.
00635 CUT*/
00636   pSymbolList p;
00637 
00638   p = pCO->pGetParameters;
00639   while( p ){
00640     if( !strcmp(p->symbol,pszParam) )return p->value ? p->value : "";
00641     p = p->next;
00642     }
00643 
00644   return NULL;
00645   }
00646 
00647 /*POD
00648 =section PostParamEx
00649 =H Query POST parameter extended
00650 =abstract
00651 Use this function to get the next value of a POST parameter if the parameter is expected to be present
00652 in the HTTP request more than once.
00653 =end
00654 
00655 This function gets the next value of the POST parameter. The name of the POST parameter should be
00656 given by the string T<pszParam>. If T<pszParam> is NULL the next parameter is returned without name comparison.
00657 This way a program can retrieve all the CGI parameters.
00658 The pointer T<p> should point to a pointer. This pointer 
00659 (the one that T<p> points to and not T<p>) should be
00660 initialized to NULL before the first call and should not be modified between calls.
00661 
00662 The function searches the next occurence of the parameter and returns a pointer to the constant
00663 string containing the value of theparameter or NULL if the parameter has no more occurence.
00664 /*FUNCTION*/
00665 char *cgi_PostParamEx(pCgiObject pCO,
00666                       char *pszParam,
00667                       pSymbolList *p
00668   ){
00669 /*noverbatim
00670 If a parameter is not expected to appear more than once use the function R<PostParam>.
00671 CUT*/
00672   if( *p == NULL )
00673     *p = pCO->pPostParameters;
00674   else
00675     *p = (*p)->next;
00676   while( *p ){
00677     if( !pszParam || !strcmp((*p)->symbol,pszParam) )
00678       return (*p)->value ? (*p)->value : "";
00679 
00680     *p = (*p)->next;
00681     }
00682 
00683   return NULL;
00684   }
00685 
00686 /*POD
00687 =section GetParamEx
00688 =H Query GET parameter extended
00689 =abstract
00690 Use this function to get the next value of a GET parameter if the parameter is expected to be present
00691 in the HTTP request more than once.
00692 =end
00693 
00694 This function gets the next value of the GET parameter. The name of the GET parameter should be
00695 given by the string T<pszParam>. If T<pszParam> is NULL the next parameter is returned without name comparison.
00696 This way a program can retrieve all the CGI parameters.
00697 The pointer T<p> should point to a pointer. This pointer 
00698 (the one that T<p> points to and not T<p>) should be
00699 initialized to NULL before the first call and should not be modified between calls.
00700 
00701 The function searches the next occurence of the parameter and returns a pointer to the constant
00702 string containing the value of theparameter or NULL if the parameter has no more occurence.
00703 /*FUNCTION*/
00704 char *cgi_GetParamEx(pCgiObject pCO,
00705                      char *pszParam,
00706                      pSymbolList *p
00707   ){
00708 /*noverbatim
00709 If a parameter is not expected to appear more than once use the function R<GetParam>.
00710 CUT*/
00711   if( *p == NULL )
00712     *p = pCO->pGetParameters;
00713   else
00714     *p = (*p)->next;
00715   while( *p ){
00716     if( !pszParam || !strcmp((*p)->symbol,pszParam) )
00717       return (*p)->value ? (*p)->value : "";
00718 
00719     *p = (*p)->next;
00720     }
00721 
00722   return NULL;
00723   }
00724 
00725 /*POD
00726 =section FILEp
00727 =H Query a POST parameter
00728 =abstract
00729 Use this function to get the file pointer to the temporary uploaded file.
00730 =end
00731 
00732 The argument T<pszParam> should point to a zchar string
00733 containing the name of a POST parameter, which is an uploaded
00734 file and is stored in a temporary file.
00735 
00736 /*FUNCTION*/
00737 FILE *cgi_FILEp(pCgiObject pCO,
00738                 char *pszParam
00739   ){
00740 /*noverbatim
00741 CUT*/
00742   pSymbolList p;
00743 
00744   p = pCO->pPostParameters;
00745   while( p ){
00746     if( !strcmp(p->symbol,pszParam) )return p->fp;
00747     p = p->next;
00748     }
00749   return NULL;
00750   }
00751 
00752 /*POD
00753 =section OriginalFileName
00754 =H Query a POST parameter
00755 =abstract
00756 Use this function to get the file name of an uploaded file.
00757 =end
00758 
00759 The argument T<pszParam> should point to a zchar string
00760 containing the name of a POST parameter, which is an uploaded
00761 file and is stored in a temporary file.
00762 
00763 The return value points to a zchar string containing the original
00764 file name as it was given in the header T<Content-Disposition>.
00765 
00766 /*FUNCTION*/
00767 char *cgi_OriginalFileName(pCgiObject pCO,
00768                 char *pszParam
00769   ){
00770 /*noverbatim
00771 CUT*/
00772   pSymbolList p;
00773 
00774   p = pCO->pPostParameters;
00775   while( p ){
00776     if( !strcmp(p->symbol,pszParam) )return p->file;
00777     p = p->next;
00778     }
00779 
00780   return NULL;
00781   }
00782 
00783 /*POD
00784 =section FileLength
00785 =H Query the length of an uploaded file
00786 =abstract
00787 Use this function to get the length of an uploaded file.
00788 =end
00789 
00790 The argument T<pszParam> should point to a zchar string
00791 containing the name of a POST parameter, which is an uploaded
00792 file and is stored in a temporary file.
00793 
00794 The return value is a long, which is the number of characters in the
00795 uploaded file.
00796 
00797 /*FUNCTION*/
00798 long cgi_FileLength(pCgiObject pCO,
00799                 char *pszParam
00800   ){
00801 /*noverbatim
00802 CUT*/
00803   pSymbolList p;
00804 
00805   p = pCO->pPostParameters;
00806   while( p ){
00807     if( !strcmp(p->symbol,pszParam) )return p->len;
00808     p = p->next;
00809     }
00810 
00811   return 0;
00812   }
00813 
00814 /*POD
00815 =section PartHeader
00816 =H Query a POST parameter
00817 =abstract
00818 Use this function to get the pointer to the header of a multipart part.
00819 =end
00820 
00821 The argument T<pszParam> should point to a zchar string
00822 containing the name of a POST parameter, which is an uploaded
00823 file and is stored in a temporary file.
00824 
00825 The return value points to header list. This pointer should be used as an argument to
00826 the function R<Header>.
00827 
00828 /*FUNCTION*/
00829 pSymbolList cgi_PartHeader(pCgiObject pCO,
00830                      char *pszParam
00831   ){
00832 /*noverbatim
00833 CUT*/
00834   pSymbolList p;
00835 
00836   p = pCO->pPostParameters;
00837   while( p ){
00838     if( !strcmp(p->symbol,pszParam) )return p->pHeaders;
00839     p = p->next;
00840     }
00841 
00842   return NULL;
00843   }
00844 
00845 /*POD
00846 =section Header
00847 =H Get a header value
00848 
00849 This function returns a pointer to a zero terminated string containing
00850 the value associated with the reqiested header field, or returns NULL
00851 if the header was not present.
00852 
00853 The argument T<symbol> shoud point to a ZCHAR string containing the
00854 header symbol we search. The header is searched case insensitive, therefore
00855 T<Content-Type> and T<Content-type> are equivalent.
00856 
00857 B<Never use the trailing colon> after the header name.
00858 
00859 The third parameter T<pHeader> should point to a header list. Such a hreader
00860 list ids returned by the function R<ReadHeader> when a multipart form data
00861 is read and stored for the uploaded file information.
00862 /*FUNCTION*/
00863 char *cgi_Header(pCgiObject pCO,
00864                  char *symbol,
00865                  pSymbolList pHeader
00866   ){
00867 /*noverbatim
00868 CUT*/
00869   while( pHeader ){
00870     if( ! stricmp(pHeader->symbol,symbol) )return pHeader->value;
00871     pHeader = pHeader->next;
00872     }
00873   return NULL;
00874   }
00875 
00876 /*POD
00877 =section Environment
00878 =H Functions to return the usual environment variables
00879 =abstract
00880 Get the values of several CGI environment variables.
00881 =end
00882 
00883 These functions return the usual environment variables
00884 of a CGI program. The CGI code should call these functions
00885 and don't call T<getenv> directly because calling these
00886 functions hide the interface and the application programs
00887 can be easily ported to run using ISAPI, NSAPI, FCGI etc.
00888 The functions provided:
00889 
00890 =itemize
00891 =item T<ServerSoftware>
00892 =item T<ServerName>
00893 =item T<GatewayInterface>
00894 =item T<ServerProtocol>
00895 =item T<ServerPort>
00896 =item T<RequestMethod>
00897 =item T<PathInfo>
00898 =item T<PathTranslated>
00899 =item T<ScriptName>
00900 =item T<QueryString>
00901 =item T<RemoteHost>
00902 =item T<RemoteAddress>
00903 =item T<AuthType>
00904 =item T<RemoteUser>
00905 =item T<RemoteIdent>
00906 =item T<ContentType>
00907 =item T<ContentLength>
00908 =item T<UserAgent>
00909 =item T<Cookie>
00910 =noitemize
00911 
00912 CUT*/
00913 
00914 #define ISAPIVAR(X,Y) \
00915       if( pCO->pDebugInfo->X )return pCO->pDebugInfo->X;\
00916       { DWORD cbBuffer;\
00917       cbBuffer = 0;\
00918       pCO->lpECB->GetServerVariable(pCO->lpECB->ConnID,Y,NULL,&cbBuffer);\
00919       if( cbBuffer == 0 )return NULL;\
00920       pCO->pDebugInfo->X = ALLOC(cbBuffer);\
00921       if( pCO->pDebugInfo->X == NULL )return NULL;\
00922       pCO->lpECB->GetServerVariable(pCO->lpECB->ConnID,Y,pCO->pDebugInfo->X,&cbBuffer);\
00923       return pCO->pDebugInfo->X;}
00924 
00925 /*FUNCTION*/
00926 char *cgi_Referer(pCgiObject pCO
00927   ){
00928   switch( pCO->fInterface ){
00929     case CGI_INTERFACE_CGI:
00930       return _getenv("HTTP_REFERER");
00931 #ifdef WIN32
00932     case CGI_INTERFACE_ISAPI:
00933       ISAPIVAR(Cookie,"HTTP_REFERER")
00934 #endif
00935     case CGI_INTERFACE_NSAPI:
00936       return NULL;
00937     case CGI_INTERFACE_FCGI:
00938       return NULL;
00939     case CGI_INTERFACE_DEBUG:
00940       return NULL;
00941     }
00942   return NULL;
00943   }
00944 
00945 /*FUNCTION*/
00946 char *cgi_Cookie(pCgiObject pCO
00947   ){
00948   switch( pCO->fInterface ){
00949     case CGI_INTERFACE_CGI:
00950       return _getenv("HTTP_COOKIE");
00951 #ifdef WIN32
00952     case CGI_INTERFACE_ISAPI:
00953       ISAPIVAR(Cookie,"HTTP_COOKIE")
00954 #endif
00955     case CGI_INTERFACE_NSAPI:
00956       return NULL;
00957     case CGI_INTERFACE_FCGI:
00958       return NULL;
00959     case CGI_INTERFACE_DEBUG:
00960       return pCO->pDebugInfo->Cookie;
00961     }
00962   return NULL;
00963   }
00964 
00965 /*FUNCTION*/
00966 char *cgi_ServerSoftware(pCgiObject pCO
00967   ){
00968 
00969   switch( pCO->fInterface ){
00970     case CGI_INTERFACE_CGI:
00971       return _getenv("SERVER_SOFTWARE");
00972 #ifdef WIN32
00973     case CGI_INTERFACE_ISAPI:
00974       ISAPIVAR(ServerSoftware,"SERVER_SOFTWARE")
00975 #endif
00976     case CGI_INTERFACE_NSAPI:
00977       return NULL;
00978     case CGI_INTERFACE_FCGI:
00979       return NULL;
00980     case CGI_INTERFACE_DEBUG:
00981       return pCO->pDebugInfo->ServerSoftware;
00982     }
00983   return NULL;
00984   }
00985 
00986 /*FUNCTION*/
00987 char *cgi_ServerName(pCgiObject pCO
00988   ){
00989 
00990   switch( pCO->fInterface ){
00991     case CGI_INTERFACE_CGI:
00992       return _getenv("SERVER_NAME");
00993 #ifdef WIN32
00994     case CGI_INTERFACE_ISAPI:
00995       ISAPIVAR(ServerName,"SERVER_NAME")
00996 #endif
00997     case CGI_INTERFACE_NSAPI:
00998       return NULL;
00999     case CGI_INTERFACE_FCGI:
01000       return NULL;
01001     case CGI_INTERFACE_DEBUG:
01002       return pCO->pDebugInfo->ServerName;
01003     }
01004   return NULL;
01005   }
01006 
01007 /*FUNCTION*/
01008 char *cgi_GatewayInterface(pCgiObject pCO
01009   ){
01010 
01011   switch( pCO->fInterface ){
01012     case CGI_INTERFACE_CGI:
01013       return _getenv("GATEWAY_INTERFACE");
01014 #ifdef WIN32
01015     case CGI_INTERFACE_ISAPI:
01016       return "ISAPI";
01017 #endif
01018     case CGI_INTERFACE_NSAPI:
01019       return NULL;
01020     case CGI_INTERFACE_FCGI:
01021       return NULL;
01022     case CGI_INTERFACE_DEBUG:
01023       return pCO->pDebugInfo->GatewayInterface;
01024     }
01025   return NULL;
01026   }
01027 
01028 /*FUNCTION*/
01029 char *cgi_ServerProtocol(pCgiObject pCO
01030   ){
01031 
01032   switch( pCO->fInterface ){
01033     case CGI_INTERFACE_CGI:
01034       return _getenv("SERVER_PROTOCOL");
01035 #ifdef WIN32
01036     case CGI_INTERFACE_ISAPI:
01037       ISAPIVAR(ServerProtocol,"SERVER_PROTOCOL")
01038 #endif
01039     case CGI_INTERFACE_NSAPI:
01040       return NULL;
01041     case CGI_INTERFACE_FCGI:
01042       return NULL;
01043     case CGI_INTERFACE_DEBUG:
01044       return pCO->pDebugInfo->ServerProtocol;
01045     }
01046   return NULL;
01047   }
01048 
01049 /*FUNCTION*/
01050 char *cgi_ServerPort(pCgiObject pCO
01051   ){
01052 
01053   switch( pCO->fInterface ){
01054     case CGI_INTERFACE_CGI:
01055       return _getenv("SERVER_PORT");
01056 #ifdef WIN32
01057     case CGI_INTERFACE_ISAPI:
01058       ISAPIVAR(ServerPort,"SERVER_PORT")
01059 #endif
01060     case CGI_INTERFACE_NSAPI:
01061       return NULL;
01062     case CGI_INTERFACE_FCGI:
01063       return NULL;
01064     case CGI_INTERFACE_DEBUG:
01065       return pCO->pDebugInfo->ServerPort;
01066     }
01067   return NULL;
01068   }
01069 
01070 /*FUNCTION*/
01071 char *cgi_RequestMethod(pCgiObject pCO
01072   ){
01073 
01074   switch( pCO->fInterface ){
01075     case CGI_INTERFACE_CGI:
01076       return _getenv("REQUEST_METHOD");
01077 #ifdef WIN32
01078     case CGI_INTERFACE_ISAPI:
01079       ISAPIVAR(RequestMethod,"REQUEST_METHOD");
01080 #endif
01081     case CGI_INTERFACE_NSAPI:
01082       return NULL;
01083     case CGI_INTERFACE_FCGI:
01084       return NULL;
01085     case CGI_INTERFACE_DEBUG:
01086       return pCO->pDebugInfo->RequestMethod;
01087     }
01088   return NULL;
01089   }
01090 
01091 /*FUNCTION*/
01092 char *cgi_PathInfo(pCgiObject pCO
01093   ){
01094 
01095   switch( pCO->fInterface ){
01096     case CGI_INTERFACE_CGI:
01097       return _getenv("PATH_INFO");
01098 #ifdef WIN32
01099     case CGI_INTERFACE_ISAPI:
01100       ISAPIVAR(PathInfo,"PATH_INFO")
01101 #endif
01102     case CGI_INTERFACE_NSAPI:
01103       return NULL;
01104     case CGI_INTERFACE_FCGI:
01105       return NULL;
01106     case CGI_INTERFACE_DEBUG:
01107       return pCO->pDebugInfo->PathInfo;
01108     }
01109   return NULL;
01110   }
01111 
01112 /*FUNCTION*/
01113 char *cgi_PathTranslated(pCgiObject pCO
01114   ){
01115 
01116   switch( pCO->fInterface ){
01117     case CGI_INTERFACE_CGI:
01118       return _getenv("PATH_TRANSLATED");
01119 #ifdef WIN32
01120     case CGI_INTERFACE_ISAPI:
01121       ISAPIVAR(PathTranslated,"PATH_TRANSLATED")
01122 #endif
01123     case CGI_INTERFACE_NSAPI:
01124       return NULL;
01125     case CGI_INTERFACE_FCGI:
01126       return NULL;
01127     case CGI_INTERFACE_DEBUG:
01128       return pCO->pDebugInfo->PathTranslated;
01129     }
01130   return NULL;
01131   }
01132 
01133 /*FUNCTION*/
01134 char *cgi_ScriptName(pCgiObject pCO
01135   ){
01136 
01137   switch( pCO->fInterface ){
01138     case CGI_INTERFACE_CGI:
01139       return _getenv("SCRIPT_NAME");
01140 #ifdef WIN32
01141     case CGI_INTERFACE_ISAPI:
01142       ISAPIVAR(ScriptName,"SCRIPT_NAME")
01143 #endif
01144     case CGI_INTERFACE_NSAPI:
01145       return NULL;
01146     case CGI_INTERFACE_FCGI:
01147       return NULL;
01148     case CGI_INTERFACE_DEBUG:
01149       return pCO->pDebugInfo->ScriptName;
01150     }
01151   return NULL;
01152   }
01153 
01154 /*FUNCTION*/
01155 char *cgi_QueryString(pCgiObject pCO
01156   ){
01157 
01158   switch( pCO->fInterface ){
01159     case CGI_INTERFACE_CGI:
01160       return _getenv("QUERY_STRING");
01161 #ifdef WIN32
01162     case CGI_INTERFACE_ISAPI:
01163       ISAPIVAR(QueryString,"QUERY_STRING")
01164 #endif
01165     case CGI_INTERFACE_NSAPI:
01166       return NULL;
01167     case CGI_INTERFACE_FCGI:
01168       return NULL;
01169     case CGI_INTERFACE_DEBUG:
01170       return pCO->pDebugInfo->QueryString;
01171     }
01172   return NULL;
01173   }
01174 
01175 /*FUNCTION*/
01176 char *cgi_RemoteHost(pCgiObject pCO
01177   ){
01178 
01179   switch( pCO->fInterface ){
01180     case CGI_INTERFACE_CGI:
01181       return _getenv("REMOTE_HOST");
01182 #ifdef WIN32
01183     case CGI_INTERFACE_ISAPI:
01184       ISAPIVAR(RemoteHost,"REMOTE_HOST")
01185 #endif
01186     case CGI_INTERFACE_NSAPI:
01187       return NULL;
01188     case CGI_INTERFACE_FCGI:
01189       return NULL;
01190     case CGI_INTERFACE_DEBUG:
01191       return pCO->pDebugInfo->RemoteHost;
01192     }
01193   return NULL;
01194   }
01195 
01196 /*FUNCTION*/
01197 char *cgi_RemoteAddress(pCgiObject pCO
01198   ){
01199 
01200   switch( pCO->fInterface ){
01201     case CGI_INTERFACE_CGI:
01202       return _getenv("REMOTE_ADDR");
01203 #ifdef WIN32
01204     case CGI_INTERFACE_ISAPI:
01205       ISAPIVAR(RemoteAddress,"REMOTE_ADDR")
01206 #endif
01207     case CGI_INTERFACE_NSAPI:
01208       return NULL;
01209     case CGI_INTERFACE_FCGI:
01210       return NULL;
01211     case CGI_INTERFACE_DEBUG:
01212       return pCO->pDebugInfo->RemoteAddress;
01213     }
01214   return NULL;
01215   }
01216 
01217 /*FUNCTION*/
01218 char *cgi_AuthType(pCgiObject pCO
01219   ){
01220 
01221   switch( pCO->fInterface ){
01222     case CGI_INTERFACE_CGI:
01223       return _getenv("AUTH_TYPE");
01224 #ifdef WIN32
01225     case CGI_INTERFACE_ISAPI:
01226       ISAPIVAR(AuthType,"AUTH_TYPE")
01227 #endif
01228     case CGI_INTERFACE_NSAPI:
01229       return NULL;
01230     case CGI_INTERFACE_FCGI:
01231       return NULL;
01232     case CGI_INTERFACE_DEBUG:
01233       return pCO->pDebugInfo->AuthType;
01234     }
01235   return NULL;
01236   }
01237 
01238 /*FUNCTION*/
01239 char *cgi_RemoteUser(pCgiObject pCO
01240   ){
01241 
01242   switch( pCO->fInterface ){
01243     case CGI_INTERFACE_CGI:
01244       return _getenv("REMOTE_USER");
01245 #ifdef WIN32
01246     case CGI_INTERFACE_ISAPI:
01247       ISAPIVAR(RemoteUser,"REMOTE_USER")
01248 #endif
01249     case CGI_INTERFACE_NSAPI:
01250       return NULL;
01251     case CGI_INTERFACE_FCGI:
01252       return NULL;
01253     case CGI_INTERFACE_DEBUG:
01254       return pCO->pDebugInfo->RemoteUser;
01255     }
01256   return NULL;
01257   }
01258 
01259 /*FUNCTION*/
01260 char *cgi_RemoteIdent(pCgiObject pCO
01261   ){
01262 
01263   switch( pCO->fInterface ){
01264     case CGI_INTERFACE_CGI:
01265       return _getenv("REMOTE_IDENT");
01266 #ifdef WIN32
01267     case CGI_INTERFACE_ISAPI:
01268       return NULL;
01269 #endif
01270     case CGI_INTERFACE_NSAPI:
01271       return NULL;
01272     case CGI_INTERFACE_FCGI:
01273       return NULL;
01274     case CGI_INTERFACE_DEBUG:
01275       return pCO->pDebugInfo->RemoteIdent;
01276     }
01277   return NULL;
01278   }
01279 
01280 /*FUNCTION*/
01281 char *cgi_ContentType(pCgiObject pCO
01282   ){
01283 
01284   switch( pCO->fInterface ){
01285     case CGI_INTERFACE_CGI:
01286       return _getenv("CONTENT_TYPE");
01287 #ifdef WIN32
01288     case CGI_INTERFACE_ISAPI:
01289       ISAPIVAR(ContentType,"CONTENT_TYPE")
01290 #endif
01291     case CGI_INTERFACE_NSAPI:
01292       return NULL;
01293     case CGI_INTERFACE_FCGI:
01294       return NULL;
01295     case CGI_INTERFACE_DEBUG:
01296       return pCO->pDebugInfo->ContentType;
01297     }
01298   return NULL;
01299   }
01300 
01301 /*FUNCTION*/
01302 char *cgi_ContentLength(pCgiObject pCO
01303   ){
01304 
01305   switch( pCO->fInterface ){
01306     case CGI_INTERFACE_CGI:
01307       return _getenv("CONTENT_LENGTH");
01308 #ifdef WIN32
01309     case CGI_INTERFACE_ISAPI:
01310       ISAPIVAR(ContentLength,"CONTENT_LENGTH")
01311 #endif
01312     case CGI_INTERFACE_NSAPI:
01313       return NULL;
01314     case CGI_INTERFACE_FCGI:
01315       return NULL;
01316     case CGI_INTERFACE_DEBUG:
01317       return pCO->pDebugInfo->ContentLength;
01318     }
01319   return NULL;
01320   }
01321 
01322 /*FUNCTION*/
01323 char *cgi_UserAgent(pCgiObject pCO
01324   ){
01325 
01326   switch( pCO->fInterface ){
01327     case CGI_INTERFACE_CGI:
01328       return _getenv("HTTP_USER_AGENT");
01329 #ifdef WIN32
01330     case CGI_INTERFACE_ISAPI:
01331       return NULL;
01332 #endif
01333     case CGI_INTERFACE_NSAPI:
01334       return NULL;
01335     case CGI_INTERFACE_FCGI:
01336       return NULL;
01337     case CGI_INTERFACE_DEBUG:
01338       return pCO->pDebugInfo->UserAgent;
01339     }
01340   return NULL;
01341   }
01342 
01343 /*POD
01344 =section ------------------------------------------------------------------------------------------
01345 CUT*/
01346 
01347 /*POD
01348 =section Buffer
01349 =H Input handling buffer
01350 
01351 CGI input handling is a sophisticated task especially when upload data
01352 in form of multi-part data is handled. To handle the data efficiently a
01353 buffer is implemented in this module. The buffer is a piece of memory
01354 pointed by the field T<pszBuffer>. The actual size of the buffer is given
01355 by the field T<cbBuffer>. The first T<cbFill> characters are actually
01356 filled in the buffer, the rest of the buffer should be treated as garbage.
01357 The start characters of the buffer upto T<lBufferPosition> should be
01358 treated as already removed from the buffer. The "string" in the buffer is
01359 binary and is NOT zchar terminated.
01360 
01361 Not all the functions handle the buffer exactly the same way, but they are
01362 consistent as they cooperate.
01363 
01364 There are simple operations that the program performs with the buffer.
01365 CUT*/
01366 
01367 /*POD
01368 =section ResizeBuffer
01369 =H Resize the object buffer
01370 
01371 The cgi object buffer is resized to accomodate at least T<lNewSize> bytes.
01372 If the buffer is already larger it just returns. If this is smaller then
01373 new space is allocated and the valid characters are copied from the start of the old buffer
01374 up to T<cbFill> characters.
01375 
01376 If there is not enough memory the buffer is untouched and the return value is
01377 zero. On success the return value is 1.
01378 
01379 /*FUNCTION*/
01380 int cgi_ResizeBuffer(pCgiObject pCO,
01381                      unsigned long lNewSize
01382   ){
01383 /*noverbatim
01384 CUT*/
01385   char *s;
01386 
01387   if( lNewSize <= pCO->cbBuffer )return 1;
01388 
01389   s = (char *)pCO->pszBuffer;
01390   pCO->pszBuffer = ALLOC(lNewSize);
01391   if( pCO->pszBuffer == NULL ){
01392     pCO->pszBuffer = (unsigned char *)s;
01393     return 0;
01394     }
01395   if( s )
01396     memcpy(pCO->pszBuffer,s,pCO->cbFill);
01397   pCO->cbBuffer = lNewSize;
01398   if( s )
01399     FREE(s);
01400   return 1;
01401   }
01402 
01403 /*POD
01404 =section FillBuffer
01405 =H Fill the buffer
01406 
01407 Fill the buffer reading the input until the buffer is full or
01408 the end of the file is reached. The buffer is NOT zchar terminated,
01409 only T<cbFill> contains the number of characters in the buffer.
01410 
01411 The function returns the number of characters read. This is zero
01412 if EOF is reached or if the buffer is full.
01413 
01414 /*FUNCTION*/
01415 long cgi_FillBuffer(pCgiObject pCO
01416   ){
01417 /*noverbatim
01418 CUT*/
01419   int ch;
01420   long lchcount;
01421 
01422   lchcount = 0;
01423   while( pCO->cbFill < pCO->cbBuffer ){
01424     ch = GETCHAR();
01425     if( ch == EOF )return lchcount;
01426     lchcount ++;
01427     pCO->pszBuffer[pCO->cbFill++] = ch;
01428     }
01429   return lchcount;
01430   }
01431 
01432 /*POD
01433 =section ShiftBuffer
01434 =H Remove characters from buffer
01435 
01436 Remove the first T<nch> characters from the buffer and shift the
01437 rest B<valid> characters to the start of the buffer.
01438 
01439 Also the field T<lBufferPosition> is moved with the characters,
01440 so it will point to the same character as before the move or
01441 to the start of the buffer if the pointed character is shifted off the
01442 buffer.
01443 
01444 The field T<cbFill> is also corrected.
01445 
01446 /*FUNCTION*/
01447 void cgi_ShiftBuffer(pCgiObject pCO,
01448                      unsigned long nch
01449   ){
01450 /*noverbatim
01451 CUT*/
01452   unsigned long i,j;
01453 
01454   if( nch == 0 )return;
01455   for( i=0, j=nch ; j < pCO->cbFill ; i++, j++ )
01456     pCO->pszBuffer[i] = pCO->pszBuffer[j];
01457   if( pCO->cbFill > nch )
01458     pCO->cbFill -= nch;
01459   else
01460     pCO->cbFill = 0;
01461   if( pCO->lBufferPosition > nch )
01462     pCO->lBufferPosition -= nch;
01463   else
01464     pCO->lBufferPosition = 0;
01465   return;
01466   }
01467 
01468 /*POD
01469 =section NormalizeBuffer
01470 =H Remove characters already passed from buffer
01471 
01472 Remove the characters from the buffer that has already been passed
01473 and are before the position T<lBufferPosition>.
01474 
01475 This function simply calls R<ShiftBuffer> to shift T<lBufferPosition>
01476 characters off from the buffer.
01477 
01478 /*FUNCTION*/
01479 void cgi_NormalizeBuffer(pCgiObject pCO
01480   ){
01481 /*noverbatim
01482 CUT*/
01483 
01484   if( pCO->lBufferPosition == 0 )return;
01485   cgi_ShiftBuffer(pCO,pCO->lBufferPosition);
01486   }
01487 
01488 /*POD
01489 =section SkipAfterBoundary
01490 =H Read up to and after the next boundary
01491 
01492 This function reads the input until the next boundary is found.
01493 
01494 Return 0 if the boundary was found and the next character is after the
01495 boundary. Return error code if the end of the file has been reached without
01496 finding a boundary or the memory allocation failed.
01497 
01498 The function uses the buffer to store the input characters and leaves the
01499 buffer filled and normalized when returns. EOF is recognized when the
01500 physical EOF is reached (the input function returns EOF) or when the
01501 boundary string followed by -- is found.
01502 
01503 /*FUNCTION*/
01504 long cgi_SkipAfterBoundary(pCgiObject pCO
01505   ){
01506 /*noverbatim
01507 CUT*/
01508   unsigned long i;
01509 
01510   /* Assure that the buffer is large enough to hold the --boundary and the
01511      CR/LF at the end of the line                                            */
01512   if( !cgi_ResizeBuffer(pCO,pCO->cbBoundary+4) )return CGI_ERROR_MEMORY_LOW; /* if memory fails */
01513 
01514   do{
01515     for( i=0 ; i+1 < pCO->cbFill ; i++ ){
01516       if( pCO->pszBuffer[i] == '-' && pCO->pszBuffer[i+1] == '-'){
01517         cgi_ShiftBuffer(pCO,i+2);
01518         cgi_FillBuffer(pCO);
01519 
01520         /* the buffer is large enough, therefore this happens only if we have reached the end
01521            of the file and there is not enough characters left to match the boundary */
01522         if( pCO->cbFill < pCO->cbBoundary )return CGI_ERROR_EOF;
01523 
01524         /* we had -- but the following characters do not match the boundary string */
01525         if( memcmp(pCO->pszBuffer,pCO->pszBoundary,pCO->cbBoundary) )
01526           continue;
01527         else{
01528           /* we have found a boundary string */
01529           if( (pCO->cbBoundary < pCO->cbFill && pCO->pszBuffer[pCO->cbBoundary] == '-') &&
01530               (pCO->cbBoundary+1 < pCO->cbFill && pCO->pszBuffer[pCO->cbBoundary+1] == '-' ) ){
01531             /* --boundary-- means EOF*/
01532             return CGI_ERROR_EOF;
01533             }
01534           if( (pCO->cbBoundary < pCO->cbFill && pCO->pszBuffer[pCO->cbBoundary] != CR) || 
01535               (pCO->cbBoundary+1 < pCO->cbFill && pCO->pszBuffer[pCO->cbBoundary+1] != LF) ){
01536             /* --boundary is not followed by CR/LF, and it should be unless we have reached end of file */
01537             continue;
01538             }
01539           if( !(pCO->cbBoundary < pCO->cbFill) )return CGI_ERROR_EOF;/* we have reached the end of file */
01540           cgi_ShiftBuffer(pCO,pCO->cbBoundary+2);/* boundary + CR/LF */
01541           cgi_FillBuffer(pCO);
01542           if( pCO->cbFill == 0 )return CGI_ERROR_EOF;/* we have reached end of file */
01543           pCO->lBufferPosition = 0;
01544           return 0;
01545           }
01546         }/*if*/
01547       }/*for*/
01548     /* we have reached the end of the buffer and did not find anything that looks like a
01549        boundary. Now drop the buffer and fill it again and go on. */
01550     cgi_EmptyBuffer(pCO);
01551     /* if there is no more characters to process, we have reached the end of the file. */
01552     if( ! cgi_FillBuffer(pCO) )return CGI_ERROR_EOF;
01553     }while(1);
01554   }
01555 
01556 /*POD
01557 =section GetNextByte
01558 =H Get the next byte from the current part
01559 
01560 Get the next byte from the input buffer when reading binary data of a multipart
01561 upload. 
01562 
01563 This function automatically gets a byte from the input buffer and fills the buffer
01564 with new data when neccesary. This function should only be used when reading the
01565 multipart data bytes. When the reading reaches a boundary the function returns EOF.
01566 
01567 Calling this function after getting EOF does not step over the boundary, the function
01568 will stay at the position on the input stream and return EOF many times. You have to call
01569 R<SkipAfterBoundary> to get after the boundary and start to read the next header.
01570 
01571 /*FUNCTION*/
01572 int cgi_GetNextByte(pCgiObject pCO
01573   ){
01574 /*noverbatim
01575 CUT*/
01576   
01577   /* Assure that the buffer is large enough to hold the boundary and the
01578      CR/LF at the end and at the start of the line
01579   */
01580   if( !cgi_ResizeBuffer(pCO,pCO->cbBoundary+6) )return EOF; /* if memory fails */
01581 
01582   /* if the buffer is empty and we can not get more characters */
01583   if( pCO->cbFill == 0  && cgi_FillBuffer(pCO) == 0 )return EOF;
01584 
01585   /* After these two lines we will have at least two characters in the buffer
01586      after the position lBufferPosition to check --boundary */
01587   if( pCO->lBufferPosition + 4 > pCO->cbFill )cgi_NormalizeBuffer(pCO);
01588   if( pCO->cbFill == 0  && cgi_FillBuffer(pCO) == 0 )return EOF;
01589   if( pCO->cbFill < 4 )cgi_FillBuffer(pCO); /* we should have at least four (CR/LF--) characters */
01590 //  if( pCO->cbFill < 4 )DebugBreak();
01591 
01592 
01593   if( pCO->pszBuffer[pCO->lBufferPosition] == CR &&
01594       pCO->lBufferPosition+1 < pCO->cbFill && /* this may be false only if there is no character on the input enough */
01595       pCO->pszBuffer[pCO->lBufferPosition+1] == LF &&
01596       pCO->lBufferPosition+2 < pCO->cbFill && 
01597       pCO->pszBuffer[pCO->lBufferPosition+2] == '-' &&
01598       pCO->lBufferPosition+3 < pCO->cbFill &&
01599       pCO->pszBuffer[pCO->lBufferPosition+3] == '-' ){
01600     /* do the check for the boundary */
01601     cgi_NormalizeBuffer(pCO);
01602 
01603     /* the buffer is large enough, therefore this happens only if we have reached the end
01604        of the file and there is not enough characters left to match the boundary */
01605     if( pCO->cbFill >= pCO->cbBoundary+4 &&
01606         !memcmp(pCO->pszBuffer+4,pCO->pszBoundary,pCO->cbBoundary) &&
01607         (
01608             (pCO->pszBuffer[pCO->cbBoundary+4] == CR && pCO->pszBuffer[pCO->cbBoundary+5] == LF )
01609           ||
01610             (pCO->pszBuffer[pCO->cbBoundary+4] == '-' && pCO->pszBuffer[pCO->cbBoundary+5] == '-' )
01611         )
01612       )return EOF;
01613     }
01614   return pCO->pszBuffer[pCO->lBufferPosition++];
01615   }
01616 
01617 /*POD
01618 =section GetNextChar
01619 =H Get the next character from the current part
01620 
01621 Get the next character from the input stream via the buffer.
01622 
01623 This function should be used when getting the next character
01624 during a normal POST operation. This function simply fills the buffer
01625 when neccesary and returns the next character until EOF. When EOF is
01626 reached the function returns EOF.
01627 
01628 No multipart handling or anything like that.
01629 
01630 /*FUNCTION*/
01631 int cgi_GetNextChar(pCgiObject pCO
01632   ){
01633 /*noverbatim
01634 CUT*/
01635   
01636   if( pCO->cbBuffer == 0  && !cgi_ResizeBuffer(pCO,pCO->lBufferIncrease) )return EOF; /* if memory fails */
01637 
01638   /* if the buffer is empty and we can not get more characters */
01639   if( pCO->cbFill == 0  && cgi_FillBuffer(pCO) == 0 )return EOF;
01640 
01641   if( pCO->lBufferPosition >= pCO->cbFill ){
01642     cgi_EmptyBuffer(pCO);
01643     if( cgi_FillBuffer(pCO) == 0 )return EOF;
01644     }
01645   return pCO->pszBuffer[pCO->lBufferPosition++];
01646   }
01647 
01648 /*POD
01649 =section ReadHeader
01650 =H Read header information until CR/LF/CR/LF sequence is found
01651 
01652 This function is used to read the header information of a
01653 multipart form data encoded upload. When the multipart form
01654 data format is used each part has a header after the preceeding
01655 boundary string separated by double CR/LF from the body of the part.
01656 
01657 Return 0 if OK,
01658 
01659 error code if error occured.
01660 
01661 The argument T<pHeader> should point to a pointer (not the pointer, but
01662 the address of the pointer). The pointer that the argument points to should
01663 be initialized with NULL (or point to a list which is appended to the result list).
01664 
01665 The pointer will point to the head of the header list upon return.
01666 
01667 /*FUNCTION*/
01668 long cgi_ReadHeader(pCgiObject pCO,
01669                    pSymbolList *pHeader
01670   ){
01671 /*noverbatim
01672 CUT*/
01673   unsigned long i,j,k,w;
01674   char *pszHeader,*pszValue;
01675   char *pszHeaderBuffer;
01676 
01677   cgi_NormalizeBuffer(pCO);
01678   /* search the CR/LF/CR/LF sequence and set i to point to the first CR 
01679      increase the buffer to hold all the header. */
01680   i = 0;
01681   do{
01682     if( i+4 >= pCO->cbFill ){/* we want to look 4 characters ahead */
01683       if( pCO->cbFill == pCO->cbBuffer )/* the buffer is full we have to increase it */
01684         if( pCO->cbBuffer+pCO->lBufferIncrease > pCO->lBufferMax )return CGI_ERROR_BUFFER_OVERFLOW;
01685         if( !cgi_ResizeBuffer(pCO,pCO->cbBuffer+pCO->lBufferIncrease) )return CGI_ERROR_MEMORY_LOW;
01686       if( cgi_FillBuffer(pCO) == 0 )return CGI_ERROR_ILLF_MULTI1;/* The buffer is not full, it is EOF */
01687       }
01688     if( pCO->pszBuffer[i+0] == CR &&
01689         pCO->pszBuffer[i+1] == LF &&
01690         pCO->pszBuffer[i+2] == CR &&
01691         pCO->pszBuffer[i+3] == LF )break;
01692     i++;
01693     }while(1);
01694 
01695   /* Now convert continuation lines of the header. */
01696   for( j = 0 ; j < i ; j++ ){
01697     if( pCO->pszBuffer[j+0] == CR &&
01698         pCO->pszBuffer[j+1] == LF &&
01699         isspace(pCO->pszBuffer[j+2]) ){
01700       pCO->pszBuffer[j] = ' ';
01701       /* search the first non space on the continuation line */
01702       for( k=j+3 ; k < i && isspace(pCO->pszBuffer[k]) ; k++ )continue;
01703       /* pull down the rest */
01704       for( w=j+1 ; k < pCO->cbFill ; w++, k++ )
01705         pCO->pszBuffer[w] = pCO->pszBuffer[k];
01706       /* correct cbFill and i */
01707       pCO->cbFill -= k-w;
01708       i -= k-w;
01709       }
01710     }
01711 
01712   pszHeaderBuffer = ALLOC(sizeof(char)*i+1);/* the final terminating zero is the +1 */
01713   if( pszHeaderBuffer == NULL )return CGI_ERROR_MEMORY_LOW;
01714   memcpy(pszHeaderBuffer,pCO->pszBuffer,i+1);/* shift off the header and the CR/LF/CR/LF */
01715   cgi_ShiftBuffer(pCO,i+4);
01716 
01717   k = 0;
01718   while( k<=i ){
01719     pszHeader = pszHeaderBuffer+k;
01720     while( k<=i && pszHeaderBuffer[k] != ':' )k++;
01721     if( !(k<=i) )return CGI_ERROR_ILLF_MULTI2;
01722     pszHeaderBuffer[k] = (char)0;/* terminate the header name */
01723     k++;
01724     while( k<=i && isspace(pszHeaderBuffer[k]) )k++;
01725     if( !(k<=i) )return CGI_ERROR_ILLF_MULTI3;
01726     pszValue = pszHeaderBuffer+k;
01727     while( k<=i && pszHeaderBuffer[k] != CR )k++;
01728     if( !(k<=i) )return CGI_ERROR_ILLF_MULTI4;
01729     pszHeaderBuffer[k] = (char)0;/* terminate the header value */
01730     *pHeader = ALLOC(sizeof(SymbolList));
01731     if( *pHeader == NULL )return CGI_ERROR_ILLF_MULTI5;
01732     (*pHeader)->symbol = pszHeader;
01733     (*pHeader)->value  = pszValue;
01734     (*pHeader)->fp  = NULL;
01735     (*pHeader)->file = NULL;
01736     (*pHeader)->next = NULL;
01737     pHeader = &((*pHeader)->next);
01738     if( !(k<=i) )return 0;
01739     k++;
01740     while( k<=i && (pszHeaderBuffer[k] == CR || pszHeaderBuffer[k] == LF) )k++;
01741     }
01742   return 0;
01743   }
01744 
01745 /*POD
01746 =section ResizeThisBuffer
01747 =H Resize a buffer other than the CGI input buffer
01748 
01749 This function is to be used to allocate a new buffer or
01750 to resize an existing buffer. The argument T<ppszBuffer>
01751 points to the old buffer, T<plOldSize> points to the size
01752 of the buffer. A new memory is allocated, the old content
01753 is copied to the new location, and the size of the buffer
01754 is set to the allocated value. The return value is true
01755 upon success and false if memory allocation fails.
01756 
01757 /*FUNCTION*/
01758 int cgi_ResizeThisBuffer(pCgiObject pCO,
01759                          char **ppszBuffer,
01760                          long *plOldSize,
01761                          long lNewSize
01762   ){
01763 /*noverbatim
01764 CUT*/
01765   char *s;
01766 
01767   if( lNewSize <= *plOldSize )return 1;
01768 
01769   s = *ppszBuffer;
01770   *ppszBuffer = ALLOC(lNewSize);
01771   if( *ppszBuffer == NULL ){
01772     *ppszBuffer = s;
01773     return 0;
01774     }
01775   memcpy(*ppszBuffer,s,*plOldSize);
01776   *plOldSize = lNewSize;
01777   if( s )
01778     FREE(s);
01779   return 1;
01780   }
01781 
01782 /*POD
01783 =section FillSymbolAndFile
01784 =H Fill the symbol and file field of a header struct
01785 
01786 This aux function gets a string that stands in the header field
01787 T<Content-Disposition> of a part of a multi part form data upload
01788 and fills the T<symbol> and T<file> field of the structure that holds
01789 the data of the actual POST parameter. If the T<name=> is missing the
01790 filed T<symbol> is untouched. If the T<file=> is missing the field
01791 T<file> remains untouched.
01792 
01793 There is no return value. This function is used only at a single location
01794 and is a separate function to ease readability.
01795 /*FUNCTION*/
01796 void cgi_FillSymbolAndFile(pCgiObject pCO,
01797                            char *pszContentDisposition,
01798                            pSymbolList pHeader
01799   ){
01800 /*noverbatim
01801 CUT*/
01802   char *s,*r;
01803   long Len;
01804 
01805   if( pszContentDisposition == NULL )return;
01806 
01807   s = pszContentDisposition;
01808   while( *s && memcmp(s,"name=",5) )s++;
01809   if( !*s )goto HandleFileName;
01810   s += 5;
01811   while( *s && isspace(*s) )s++;
01812   if( *s == '\"' ){
01813     s++;
01814     r = s;
01815     while( *r && *r != '\"' )r++;
01816     }else{
01817     r = s;
01818     while( *r && *r != ';' )r++;
01819     }
01820   Len = r-s;
01821   pHeader->symbol = ALLOC(Len+1);
01822   if( pHeader->symbol == NULL )return;
01823   memcpy(pHeader->symbol,s,Len);
01824   pHeader->symbol[Len] = (char)0;
01825 
01826 HandleFileName:;
01827   s = pszContentDisposition;
01828   while( *s && memcmp(s,"filename=",9) )s++;
01829   if( !*s )return;
01830   s += 9;
01831   while( *s && isspace(*s) )s++;
01832   if( *s == '\"' ){
01833     s++;
01834     r = s;
01835     while( *r && *r != '\"' )r++;
01836     }else{
01837     r = s;
01838     while( *r && *r != ';' )r++;
01839     }
01840   Len = r-s;
01841   pHeader->file = ALLOC(Len+1);
01842   if( pHeader->file == NULL )return;
01843   memcpy(pHeader->file,s,Len);
01844   pHeader->file[Len] = (char)0;
01845   }
01846 
01847 /*POD
01848 =section GetMultipartParameters
01849 =H Get parameters from an upload
01850 
01851 This function reads the configured input and stores
01852 the POST parameters in case the content type is
01853 multipart form data.
01854 
01855 The data read is stored in the into a linked list
01856 pointed by the field T<pPostParameters>.
01857 
01858 The files uploaded are stored in temporary file. The
01859 temporary file is opened, the content is written into them,
01860 and the file pointer stored in the field T<fp> is moved to the
01861 start of the file. Closing this pointer using T<closey is
01862 supposed to delete the temporary file according to POSIX.
01863 /*FUNCTION*/
01864 long cgi_GetMultipartParameters(pCgiObject pCO
01865   ){
01866 /*noverbatim
01867 CUT*/
01868   char *s,*pszContentDisposition;
01869   unsigned long i;
01870   int ch,lErrorCode;
01871   pSymbolList pThisHeader;
01872   pSymbolList *pParamp;
01873   char *pszBuffer;
01874   unsigned long cbBuffer;
01875 
01876   /* there can be some ?a=1&b=2 part after the URL even when POST is used */
01877   cgi_GetGetParameters(pCO);
01878 
01879   s = cgi_ContentType(pCO) + 19;/* after multipart-form-data */
01880   while( *s && memcmp(s,"boundary=",9) )s++;
01881   if( *s ){
01882     pCO->pszBoundary = s+9;
01883     pCO->cbBoundary = strlen(pCO->pszBoundary);
01884     if( (lErrorCode=cgi_SkipAfterBoundary(pCO)) == CGI_ERROR_EOF )return CGI_ERROR_ILLF_MULTI6; /* EOF ? A zero part-for-data ?*/
01885     if( lErrorCode == CGI_ERROR_MEMORY_LOW )return CGI_ERROR_MEMORY_LOW;
01886     }else{
01887     /* the content type does not contain the boundary
01888        try to guess the boundary using the first line
01889        of the content that is supposed to hold the boundary */
01890     cgi_ResizeBuffer(pCO,pCO->lBufferIncrease);
01891     i = 0;
01892     do{
01893       if( ! cgi_FillBuffer(pCO) )
01894         /* we have read the whole input and no any CR/LF was found */
01895         return CGI_ERROR_ILLF_MULTI7;
01896 
01897       while( i >= pCO->cbFill-1 ){
01898         /* return if buffer grew too large or no more memory is available */
01899         if( pCO->cbBuffer+pCO->lBufferIncrease > pCO->lBufferMax )return CGI_ERROR_BUFFER_OVERFLOW;
01900         if( !cgi_ResizeBuffer(pCO,pCO->cbBuffer+pCO->lBufferIncrease) )return CGI_ERROR_MEMORY_LOW;
01901         }
01902       while( i < pCO->cbFill-1 ){
01903         if( pCO->pszBuffer[i] == CR && pCO->pszBuffer[i+1] == LF ){
01904           pCO->pszBoundary = ALLOC(i-2);
01905           if( pCO->pszBoundary == NULL )return CGI_ERROR_MEMORY_LOW;
01906           pCO->cbBoundary = i-2;
01907           memcpy(pCO->pszBoundary,pCO->pszBuffer+2,i);
01908           cgi_ShiftBuffer(pCO,i+2);
01909           goto OUTER_BREAK;
01910           }
01911         i++;
01912         }
01913       }while(1);
01914 OUTER_BREAK:;
01915     }
01916   /* now we have the boundary and are after the first boundary */
01917   cgi_ResizeBuffer(pCO,pCO->lBufferIncrease);
01918   pszBuffer = NULL;
01919   cbBuffer = 0L;
01920   pParamp = &(pCO->pPostParameters);
01921   while( 1 ){
01922     pThisHeader = NULL;
01923     if( lErrorCode = cgi_ReadHeader(pCO,&pThisHeader) )return lErrorCode;
01924     *pParamp = ALLOC(sizeof(SymbolList));
01925     if( *pParamp == NULL )return CGI_ERROR_MEMORY_LOW;
01926     (*pParamp)->symbol = NULL;
01927     (*pParamp)->file = NULL;
01928     (*pParamp)->value = NULL;
01929     (*pParamp)->fp  = NULL;
01930     (*pParamp)->file = NULL;
01931     (*pParamp)->next = NULL;
01932     (*pParamp)->pHeaders = pThisHeader;
01933 
01934     pszContentDisposition = cgi_Header(pCO,"Content-Disposition",(*pParamp)->pHeaders);
01935     /* if there is content disposition field then fill the name and the file fileds. */
01936     cgi_FillSymbolAndFile(pCO,pszContentDisposition,*pParamp);
01937     if( (*pParamp)->file ){
01938       (*pParamp)->fp = tmpfile();
01939       if( (*pParamp)->fp == NULL )return CGI_ERROR_MEMORY_LOW;
01940       i = 0;
01941       while( (ch=cgi_GetNextByte(pCO)) != EOF ){
01942         putc(ch,(*pParamp)->fp);
01943         if( ++i > pCO->lFileMax )return CGI_ERROR_FILEMAX;
01944         }
01945       (*pParamp)->len = i;
01946       fseek((*pParamp)->fp,0L,SEEK_SET);
01947       }else{
01948       cgi_ResizeThisBuffer(pCO,&pszBuffer,&cbBuffer,pCO->lBufferIncrease);
01949       i = 0;
01950       while( (ch=cgi_GetNextByte(pCO)) != EOF ){
01951         while( i >= cbBuffer-1 ){/* -1 to have space for termiating zero */
01952           if( pCO->lBufferIncrease + cbBuffer > pCO->lBufferMax )return CGI_ERROR_BUFFER_OVERFLOW;
01953           cgi_ResizeThisBuffer(pCO,&pszBuffer,&cbBuffer,cbBuffer+pCO->lBufferIncrease);
01954           }
01955         pszBuffer[i++] = ch;
01956         }
01957       pszBuffer[i] = (char)0;
01958       (*pParamp)->value = ALLOC(i+1);
01959       if( (*pParamp)->value == NULL )return CGI_ERROR_MEMORY_LOW;
01960       memcpy((*pParamp)->value,pszBuffer,i+1);
01961       }
01962     pParamp = &((*pParamp)->next);
01963     if( (lErrorCode = cgi_SkipAfterBoundary(pCO)) == CGI_ERROR_EOF ){
01964       FREE(pszBuffer);
01965       return 0;
01966       }
01967 
01968     if( lErrorCode == CGI_ERROR_MEMORY_LOW )return CGI_ERROR_MEMORY_LOW;
01969     }
01970   }
01971 
01972 /*POD
01973 =section GetGetParameters
01974 =H Get the GET parameters
01975 
01976 This function gets the GET parameters and stores them into a linked list
01977 pointed by the field T<pGetParameters>.
01978 /*FUNCTION*/
01979 long cgi_GetGetParameters(pCgiObject pCO
01980   ){
01981 /*noverbatim
01982 CUT*/
01983   char *s,*Symbol,*Value;
01984   long Len;
01985   pSymbolList *pParamp;
01986 
01987   s = cgi_QueryString(pCO);
01988   pParamp = &(pCO->pGetParameters);
01989   while( s && *s ){
01990     Symbol = s;
01991     while( *s && *s != '=' && *s != '&' )s++;
01992     Len = s - Symbol;
01993     *pParamp = ALLOC(sizeof(SymbolList));
01994     if( *pParamp == NULL )return CGI_ERROR_MEMORY_LOW;
01995     (*pParamp)->fp  = NULL;
01996     (*pParamp)->file = NULL;
01997     (*pParamp)->value = NULL;
01998     (*pParamp)->next = NULL;
01999     (*pParamp)->pHeaders = NULL;
02000     (*pParamp)->symbol = ALLOC(Len+1);
02001     if( (*pParamp)->symbol == NULL )return CGI_ERROR_MEMORY_LOW;
02002     memcpy((*pParamp)->symbol,Symbol,Len);
02003     (*pParamp)->symbol[Len] = (char)0;
02004     Len++;
02005     unescape((*pParamp)->symbol,&Len);
02006     if( !*s )break;
02007     if( *s == '=' )s++;
02008     Value = s;
02009     while( *s && *s != '&' )s++;
02010     Len = s - Value;
02011     (*pParamp)->value = ALLOC(Len+1);
02012     if( (*pParamp)->value == NULL )return CGI_ERROR_MEMORY_LOW;
02013     memcpy((*pParamp)->value,Value,Len);
02014     (*pParamp)->value[Len] = (char)0;
02015     Len++;
02016     unescape((*pParamp)->value,&Len);
02017     pParamp = &((*pParamp)->next);
02018     if( *s )s++;
02019     }
02020   return 0;
02021   }
02022 
02023 /*POD
02024 =section GetPostParameters
02025 =H Get the POST parameters
02026 
02027 This function gets the POST parameters and stores them into a linked list
02028 pointed by the field T<pPostParameters>.
02029 /*FUNCTION*/
02030 long cgi_GetPostParameters(pCgiObject pCO
02031   ){
02032 /*noverbatim
02033 CUT*/
02034   char *s,*Symbol,*Value;
02035   long Len;
02036   pSymbolList *pParamp;
02037 
02038   /* there can be some ?a=1&b=2 part after the URL even when POST is used */
02039   cgi_GetGetParameters(pCO);
02040 
02041   if( ! cgi_ResizeBuffer(pCO,pCO->lBufferIncrease) )return CGI_ERROR_MEMORY_LOW;
02042   /* read all characters into the buffer */
02043   while( cgi_FillBuffer(pCO) ){
02044     if( pCO->cbBuffer+pCO->lBufferIncrease > pCO->lBufferMax )return CGI_ERROR_BUFFER_OVERFLOW;
02045     if( !cgi_ResizeBuffer(pCO,pCO->cbBuffer+pCO->lBufferIncrease) )return CGI_ERROR_MEMORY_LOW;
02046     }
02047   s = (char *)pCO->pszBuffer;
02048   /* terminate the buffer with a zchar. We actually have pCO->lBufferIncrease number of bytes
02049      to do this */
02050   s[ pCO->cbFill ] = (char)0;
02051 
02052   pParamp = &(pCO->pPostParameters);
02053   while( *s ){
02054     Symbol = s;
02055     while( *s && *s != '=' && *s != '&' )s++;
02056     Len = s - Symbol;
02057     *pParamp = ALLOC(sizeof(SymbolList));
02058     if( *pParamp == NULL )return CGI_ERROR_MEMORY_LOW;
02059     (*pParamp)->fp  = NULL;
02060     (*pParamp)->file = NULL;
02061     (*pParamp)->value = NULL;
02062     (*pParamp)->next = NULL;
02063     (*pParamp)->pHeaders = NULL;
02064     (*pParamp)->symbol = ALLOC(Len+1);
02065     if( (*pParamp)->symbol == NULL )return CGI_ERROR_MEMORY_LOW;
02066     memcpy((*pParamp)->symbol,Symbol,Len);
02067     (*pParamp)->symbol[Len] = (char)0;
02068     Len++;
02069     unescape((*pParamp)->symbol,&Len);
02070     if( !*s )break;
02071     if( *s == '=' )s++;
02072     Value = s;
02073     while( *s && *s != '&' )s++;
02074     Len = s - Value;
02075     (*pParamp)->value = ALLOC(Len+1);
02076     if( (*pParamp)->value == NULL )return CGI_ERROR_MEMORY_LOW;
02077     memcpy((*pParamp)->value,Value,Len);
02078     (*pParamp)->value[Len] = (char)0;
02079     Len++;
02080     unescape((*pParamp)->value,&Len);
02081     pParamp = &((*pParamp)->next);
02082     if( *s )s++;
02083     }
02084   return 0;
02085   }

Generated on Sun Mar 12 23:56:29 2006 for ScriptBasic by  doxygen 1.4.6-NO