home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / software / pelne / optionp / iis4_07.cab / CGIWRAP.C < prev    next >
C/C++ Source or Header  |  1997-10-25  |  10KB  |  420 lines

  1. /*++
  2.  
  3. File: cgiwrap.c
  4.  
  5. Demonstrates an executable which can be used to load an ISAPI DLL like
  6. a CGI script.
  7.  
  8. --*/
  9.  
  10. #define WIN32_LEAN_AND_MEAN
  11. #include <windows.h>
  12. #include <httpext.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15.  
  16. //
  17. // These are things that go out in the Response Header
  18. // 
  19.  
  20. #define HTTP_VER "HTTP/1.0"
  21. #define SERVER_VERSION "Http-Srv-Beta2/1.0"
  22.  
  23. //
  24. // Simple wrappers for the heap APIS
  25. // 
  26.  
  27. #define xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s))
  28. #define xfree(s)   HeapFree(GetProcessHeap(), 0, (s))
  29.  
  30. //
  31. // The mandatory exports from the ISAPI DLL
  32. // 
  33.  
  34. typedef BOOL(WINAPI * VersionProc) (HSE_VERSION_INFO *);
  35. typedef DWORD(*HttpExtProc) (EXTENSION_CONTROL_BLOCK *);
  36.  
  37.  
  38. //
  39. // Prototypes of the functions this sample implements
  40. // 
  41.  
  42. BOOL WINAPI FillExtensionControlBlock(EXTENSION_CONTROL_BLOCK *);
  43. BOOL WINAPI GetServerVariable(HCONN, LPSTR, LPVOID, LPDWORD);
  44. BOOL WINAPI ReadClient(HCONN, LPVOID, LPDWORD);
  45. BOOL WINAPI WriteClient(HCONN, LPVOID, LPDWORD, DWORD);
  46. BOOL WINAPI ServerSupportFunction(HCONN, DWORD, LPVOID, LPDWORD, LPDWORD);
  47. char *MakeDateStr(VOID);
  48. char *GetEnv(char *);
  49.  
  50.  
  51. //
  52. // In the startup of this program, we look at our executable name and      
  53. // replace the ".EXE" with ".DLL" to find the ISAPI DLL we need to load.   
  54. // This means that the executable need only be given the same "name" as    
  55. // the DLL to load. There is no recompilation required.                    
  56. //
  57.  
  58. int __cdecl
  59. main(int argc, char **argv)
  60. {
  61.  
  62.     HINSTANCE hDll;
  63.     VersionProc GetExtensionVersion;
  64.     HttpExtProc HttpExtensionProc;
  65.     HSE_VERSION_INFO version_info;
  66.     EXTENSION_CONTROL_BLOCK ECB;
  67.     DWORD rc;
  68.     char szModuleFileName[256], *c;
  69.  
  70.  
  71.     if (!GetModuleFileName(NULL, szModuleFileName, 256)) {
  72.         fprintf(stderr, "cannot get ModuleFileName %d\n", GetLastError());
  73.         return -1;
  74.     }
  75.  
  76.     rc = strlen(szModuleFileName);
  77.     c = szModuleFileName + rc - 4;  // Go back to the last "."
  78.  
  79.     c[1] = 'D';
  80.     c[2] = 'L';
  81.     c[3] = 'L';
  82.  
  83.     hDll = LoadLibrary(szModuleFileName);   // Load our DLL
  84.  
  85.     if (!hDll) {
  86.         fprintf(stderr, "Error: Failure to load %s.dll (%d)\n",
  87.             argv[0], GetLastError());
  88.         return -1;
  89.     }
  90.  
  91.     // 
  92.     // Find the exported functions
  93.     //
  94.  
  95.     GetExtensionVersion = (VersionProc) GetProcAddress(hDll, 
  96.                                             "GetExtensionVersion");
  97.     if (!GetExtensionVersion) {
  98.         fprintf(stderr, "Can't Get Extension Version %d\n", GetLastError());
  99.         return -1;
  100.     }
  101.     HttpExtensionProc = (HttpExtProc) GetProcAddress(hDll, 
  102.                                           "HttpExtensionProc");
  103.     if (!HttpExtensionProc) {
  104.         fprintf(stderr, "Can't Get Extension proc %d\n", GetLastError());
  105.         return -1;
  106.     }
  107.  
  108.     //
  109.     // This should really check if the version information matches what 
  110.     // we expect.
  111.     // 
  112.  
  113.     __try {
  114.         if (!GetExtensionVersion(&version_info)) {
  115.             fprintf(stderr, "Fatal: GetExtensionVersion failed\n");
  116.             return -1;
  117.         }
  118.     }
  119.     __except(1) {
  120.         return -1;
  121.     }
  122.  
  123.     // 
  124.     // Fill the ECB with the necessary information
  125.     // 
  126.  
  127.     if (!FillExtensionControlBlock(&ECB)) {
  128.         fprintf(stderr, "Fill Ext Block Failed\n");
  129.         return -1;
  130.     }
  131.  
  132.     //
  133.     // Call the DLL
  134.     // 
  135.  
  136.     __try {
  137.         rc = HttpExtensionProc(&ECB);
  138.     }
  139.     __except(1) {
  140.         return -1;
  141.     }
  142.  
  143.  
  144.     //
  145.     // We should really free memory (e.g., from GetEnv), but we'll be dead
  146.     // soon enough
  147.     //
  148.     
  149.     if (rc == HSE_STATUS_PENDING)   
  150.         
  151.         //
  152.         // We will exit in ServerSupportFunction
  153.         //
  154.  
  155.         Sleep(INFINITE);
  156.  
  157.     return 0;
  158.  
  159. }
  160.  
  161.  
  162. //
  163. // GetServerVariable() is how the DLL calls the main program to figure out
  164. // the environment variables it needs. This is a required function.
  165. // 
  166.  
  167. BOOL WINAPI
  168. GetServerVariable(HCONN hConn, LPSTR lpszVariableName,
  169.     LPVOID lpBuffer, LPDWORD lpdwSize)
  170. {
  171.  
  172.     DWORD rc;
  173.  
  174.     // 
  175.     // We don't really have an HCONN, so we assume a value of 0 (which is
  176.     // passed
  177.     // to the DLL in the ECB by HttpExtensionProc().
  178.     // Hence the check for a non-zero HCONN
  179.  
  180.     if (hConn) {
  181.         SetLastError(ERROR_INVALID_PARAMETER);
  182.         return FALSE;
  183.     }
  184.     rc = GetEnvironmentVariable(lpszVariableName, lpBuffer, *lpdwSize);
  185.  
  186.     if (!rc) {                  
  187.  
  188.         //
  189.         // return of 0 indicates the variable was not found
  190.         //
  191.         SetLastError(ERROR_NO_DATA);
  192.         return FALSE;
  193.     }
  194.  
  195.     if (rc > *lpdwSize) {
  196.         SetLastError(ERROR_INSUFFICIENT_BUFFER);
  197.         return FALSE;
  198.     }
  199.  
  200.     //
  201.     // GetEnvironmentVariable does not count the NUL character
  202.     //
  203.     *lpdwSize = rc + 1;         
  204.  
  205.     return TRUE;
  206.  
  207. }
  208.  
  209.  
  210. //
  211. // Again, we don't have an HCONN, so we simply wrap ReadClient() to
  212. // ReadFile on stdin. The semantics of the two functions are the same
  213. // 
  214.  
  215. BOOL WINAPI
  216. ReadClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize)
  217. {
  218.  
  219.     return ReadFile(GetStdHandle(STD_INPUT_HANDLE), lpBuffer, (*lpdwSize),
  220.         lpdwSize, NULL);
  221.  
  222. }
  223.  
  224.  
  225. //
  226. // ditto for WriteClient()
  227. // 
  228.  
  229. BOOL WINAPI
  230. WriteClient(HCONN hConn, LPVOID lpBuffer, LPDWORD lpdwSize,
  231.     DWORD dwReserved)
  232. {
  233.  
  234.     return WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), lpBuffer, *lpdwSize,
  235.         lpdwSize, NULL);
  236.  
  237. }
  238.  
  239.  
  240. //
  241. // This is a special callback function used by the DLL for certain extra 
  242. // functionality. Look at the API help for details.
  243. // 
  244.  
  245. BOOL WINAPI
  246. ServerSupportFunction(HCONN hConn, DWORD dwHSERequest,
  247.     LPVOID lpvBuffer, LPDWORD lpdwSize, LPDWORD lpdwDataType)
  248. {
  249.  
  250.     char *lpszRespBuf;
  251.     char *temp;
  252.     DWORD dwBytes;
  253.     BOOL bRet;
  254.  
  255.     switch (dwHSERequest) {
  256.  
  257.     case (HSE_REQ_SEND_RESPONSE_HEADER):
  258.         lpszRespBuf = xmalloc(*lpdwSize + 80);  // accomodate our header
  259.  
  260.         if (!lpszRespBuf)
  261.             return FALSE;
  262.         wsprintf(lpszRespBuf, "%s %s %s %s\r\n%s", 
  263.             HTTP_VER,
  264.             lpvBuffer ? lpvBuffer : "200 Ok",   // Default response is 200 Ok
  265.             temp = MakeDateStr(),               // Create a time string
  266.             SERVER_VERSION,
  267.  
  268.         //
  269.         // If this exists, it is a pointer to a data buffer to be sent. 
  270.         //
  271.             lpdwDataType ? (char *) lpdwDataType : NULL);
  272.  
  273.         xfree(temp);
  274.  
  275.         dwBytes = strlen(lpszRespBuf);
  276.         bRet = WriteClient(0, lpszRespBuf, &dwBytes, 0);
  277.         xfree(lpszRespBuf);
  278.  
  279.         break;
  280.  
  281.  
  282.     case (HSE_REQ_DONE_WITH_SESSION):
  283.  
  284.         // 
  285.         // A real server would do cleanup here
  286.         //
  287.  
  288.         ExitProcess(0);
  289.         break;
  290.  
  291.     case (HSE_REQ_SEND_URL_REDIRECT_RESP):
  292.  
  293.         // 
  294.         // This sends a redirect (temporary) to the client.
  295.         // The header construction is similar to RESPONSE_HEADER above.
  296.         // 
  297.  
  298.         lpszRespBuf = xmalloc(*lpdwSize + 80);
  299.         if (!lpszRespBuf)
  300.             return FALSE;
  301.         wsprintf(lpszRespBuf, "%s %s %s\r\n",
  302.             HTTP_VER,
  303.             "302 Moved Temporarily",
  304.             (lpdwSize > 0) ? lpvBuffer : 0);
  305.         dwBytes = strlen(lpszRespBuf);
  306.         bRet = WriteClient(0, lpszRespBuf, &dwBytes, 0);
  307.         xfree(lpszRespBuf);
  308.         break;
  309.  
  310.     default:
  311.         return FALSE;
  312.         break;
  313.     }
  314.     return bRet;
  315.  
  316. }
  317.  
  318.  
  319.  
  320. //
  321. // Makes a string of the date and time from GetSystemTime().
  322. // This is in UTC, as required by the HTTP spec.`
  323. // 
  324.  
  325. char *
  326. MakeDateStr(void)
  327. {
  328.     SYSTEMTIME systime;
  329.     char *szDate = xmalloc(64);
  330.  
  331.     char *DaysofWeek[] = 
  332.         {"Sun", "Mon", "Tue", "Wed", "Thurs", "Fri", "Sat"};
  333.     char *Months[] = 
  334.         {"NULL", "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
  335.          "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  336.  
  337.     GetSystemTime(&systime);
  338.  
  339.     wsprintf(szDate, "%s, %d %s %d %d:%d.%d", 
  340.         DaysofWeek[systime.wDayOfWeek],
  341.         systime.wDay,
  342.         Months[systime.wMonth],
  343.         systime.wYear,
  344.         systime.wHour, systime.wMinute,
  345.         systime.wSecond);
  346.  
  347.     return szDate;
  348. }
  349.  
  350.  
  351. //
  352. // Fill the ECB up 
  353. // 
  354.  
  355. BOOL WINAPI
  356. FillExtensionControlBlock(EXTENSION_CONTROL_BLOCK * ECB)
  357. {
  358.  
  359.     char *temp;
  360.  
  361.     ECB->cbSize = sizeof (EXTENSION_CONTROL_BLOCK);
  362.     ECB->dwVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  363.     ECB->ConnID = 0;
  364.  
  365.     // 
  366.     // Pointers to the functions the DLL will call.
  367.     // 
  368.     
  369.     ECB->GetServerVariable = GetServerVariable;
  370.     ECB->ReadClient = ReadClient;
  371.     ECB->WriteClient = WriteClient;
  372.     ECB->ServerSupportFunction = ServerSupportFunction;
  373.  
  374.     // 
  375.     // Fill in the standard CGI environment variables
  376.     // 
  377.     
  378.     ECB->lpszMethod = GetEnv("REQUEST_METHOD");
  379.     ECB->lpszQueryString = GetEnv("QUERY_STRING");
  380.     ECB->lpszPathInfo = GetEnv("PATH_INFO");
  381.     ECB->lpszPathTranslated = GetEnv("PATH_TRANSLATED");
  382.     ECB->cbTotalBytes = ((temp = GetEnv("CONTENT_LENGTH")) ? 
  383.                             (atoi(temp)) : 0);
  384.     ECB->cbAvailable = 0;
  385.     ECB->lpbData = "";
  386.     ECB->lpszContentType = GetEnv("CONTENT_TYPE");
  387.  
  388.     return TRUE;
  389.  
  390. }
  391.  
  392.  
  393. //
  394. // Works like _getenv(), but uses win32 functions instead.
  395. // 
  396.  
  397. char *
  398. GetEnv(LPSTR lpszEnvVar)
  399. {
  400.  
  401.     char *var, dummy;
  402.     DWORD dwLen;
  403.  
  404.     if (!lpszEnvVar)
  405.         return "";
  406.  
  407.     dwLen = GetEnvironmentVariable(lpszEnvVar, &dummy, 1);
  408.  
  409.     if (dwLen == 0)
  410.         return "";
  411.  
  412.     var = xmalloc(dwLen);
  413.     if (!var)
  414.         return "";
  415.  
  416.     (void) GetEnvironmentVariable(lpszEnvVar, var, dwLen);
  417.  
  418.     return var;
  419. }
  420.