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

  1. // Miscellaneous utility functions
  2.  
  3. #include "CkyPch.h"
  4.  
  5. #include "utils.h"
  6. #include "debug.h"
  7. #include "notify.h"
  8. #include "trie.h"
  9. #include "globals.h"
  10.  
  11.  
  12. // A list of MIME extensions that we know can safely ignore.
  13. // BUGBUG: really ought to get this list dynamically
  14.  
  15. static char* s_aszIgnoredExtensions[] = {
  16.     "evy",     "hqx",     "doc",     "dot",     "bin",
  17.     "oda",     "pdf",     "ai",      "eps",     "ps",
  18.     "rtf",     "hlp",     "bcpio",   "cpio",    "csh",
  19.     "dcr",     "dir",     "dxr",     "dvi",     "gtar",
  20.     "hdf",     "latex",   "mdb",     "crd",     "clp",
  21.     "xla",     "xlc",     "xlm",     "xls",     "xlt",
  22.     "xlw",     "m1d",     "m14",     "wmf",     "mny",
  23.     "ppt",     "mpp",     "pub",     "trm",     "wks",
  24.     "wri",     "cdf",     "nc",      "pma",     "pmc",
  25.     "pml",     "pmr",     "pmw",     "sh",      "shar",
  26.     "sv4cpio", "sv4crc",  "tar",     "tcl",     "tex",
  27.     "texi",    "texinfo", "roff",    "t",       "tr",
  28.     "man",     "me",      "ms",      "ustar",   "src",
  29.     "zip",     "au",      "snd",     "aif",     "aifc",
  30.     "aiff",    "ram",     "wav",     "bmp",     "cod",
  31.     "gif",     "ief",     "jpe",     "jpeg",    "jpg",
  32.     "tif",     "tiff",    "ras",     "cmx",     "pnm",
  33.     "pbm",     "pgm",     "ppm",     "rgb",     "xbm",
  34.     "xpm",     "xwd",     "bas",     "c",       "h",
  35.     "txt",     "rtx",     "tsv",     "etx",     "mpe",
  36.     "mpeg",    "mpg",     "mov",     "qt",      "avi",
  37.     "movie",   "flr",     "wrl",     "wrz",     "xaf",
  38.     "xof",
  39. };
  40.  
  41.  
  42. // STL functor for CStrILookup
  43.  
  44. struct stricomp {
  45.     bool
  46.     operator()(
  47.         const char* s1,
  48.         const char* s2) const
  49.     {
  50.         return stricmp(s1, s2) < 0;
  51.     }
  52. };
  53.  
  54. typedef set<const char*, stricomp> CStrILookup;
  55.  
  56. static CStrILookup s_setMimeExtensions;
  57.  
  58.  
  59. // Figure out the type of a URL (http:, mailto:, etc)
  60.  
  61. typedef struct {
  62.     const char* m_pszUrlType;
  63.     URLTYPE     m_ut;
  64.  
  65. #ifdef _DEBUG
  66.     void
  67.     AssertValid() const
  68.     {}
  69.  
  70.     void
  71.     Dump() const
  72.     {
  73.         TRACE("\t%d", m_ut);
  74.     }
  75. #endif
  76. } SUrlType;
  77.  
  78.  
  79. static const SUrlType s_aUrlTypes[] = {
  80.     {"http:",   UT_HTTP},
  81.     {"https:",  UT_HTTPS},
  82.     {"ftp:",    UT_FTP},
  83.     {"gopher:", UT_GOPHER},
  84.     {"mailto:", UT_MAILTO},
  85.     {"mk:",     UT_MK},
  86.     {"news:",   UT_NEWS},
  87.     {"newsrc:", UT_NEWSRC},
  88.     {"nntp:",   UT_NNTP},
  89.     {"telnet:", UT_TELNET},
  90.     {"wais:",   UT_WAIS},
  91. };
  92.  
  93.  
  94. static CTrie<SUrlType, true, false> s_trieUrlType;
  95.  
  96.  
  97.  
  98. //
  99. // Initialize various utility functions
  100. //
  101.  
  102. BOOL
  103. InitUtils()
  104. {
  105.     TRACE("InitUtils\n");
  106.  
  107.     // Double-check that we've set up our constants correctly
  108.     ASSERT(strlen(SESSION_ID_PREFIX) == SESSION_ID_PREFIX_SIZE);
  109.     ASSERT(strlen(SESSION_ID_SUFFIX) == SESSION_ID_SUFFIX_SIZE);
  110.     ASSERT(strlen(SZ_SESSION_ID_COOKIE_NAME)== SZ_SESSION_ID_COOKIE_NAME_SIZE);
  111.  
  112.     // Build the set of ignorable MIME extensions
  113.     s_setMimeExtensions.insert(s_aszIgnoredExtensions,
  114.                                s_aszIgnoredExtensions
  115.                                  + ARRAYSIZE(s_aszIgnoredExtensions));
  116. #ifdef _DEBUG
  117.     int cExt = 0;
  118.     for (CStrILookup::iterator j = s_setMimeExtensions.begin();
  119.          j != s_setMimeExtensions.end();
  120.          ++j)
  121.     {
  122.         const char* psz = *j;
  123.         TRACE("%s%c", psz, (++cExt & 3) ? '\t' : '\n' );
  124.     }
  125.     TRACE("\n");
  126. #endif
  127.  
  128.     for (int i = 0;  i < ARRAYSIZE(s_aUrlTypes);  ++i)
  129.         s_trieUrlType.AddToken(s_aUrlTypes[i].m_pszUrlType, &s_aUrlTypes[i]);
  130.  
  131.     DUMP(&s_trieUrlType);
  132.  
  133.     return InitEventLog();
  134. }
  135.  
  136.  
  137.  
  138. //
  139. // Clean up when terminating
  140. //
  141.  
  142. BOOL
  143. TerminateUtils()
  144. {
  145.     TRACE("TerminateUtils\n");
  146.  
  147.     // Best to clean up global objects as much as possible before terminating
  148.     s_setMimeExtensions.clear();
  149.  
  150.     return TRUE;
  151. }
  152.  
  153.  
  154.  
  155. //
  156. // Can this URL be safely ignored?
  157. //
  158.  
  159. BOOL
  160. IsIgnorableUrl(
  161.     LPCSTR pszUrl)
  162. {
  163.     // a URL ending in '/' (i.e., a directory name) is ignorable
  164.     if (pszUrl[strlen(pszUrl) - 1] == '/')
  165.         return TRUE;
  166.     
  167.     LPCSTR pszExtn = strrchr(pszUrl, '.');
  168.  
  169.     if (pszExtn != NULL)
  170.     {
  171.         return (s_setMimeExtensions.find(pszExtn + 1)
  172.                 != s_setMimeExtensions.end());
  173.     }
  174.  
  175.     return FALSE;
  176. }
  177.  
  178.  
  179.  
  180. //
  181. // "http:" -> UT_HTTP, "ftp:" -> UT_FTP, etc
  182. //
  183.  
  184. URLTYPE
  185. UrlType(
  186.     LPCTSTR ptszData,
  187.     LPCTSTR ptszEnd,
  188.     int&    rcLen)
  189. {
  190.     const SUrlType* put = s_trieUrlType.Search(ptszData, &rcLen,
  191.                                                ptszEnd - ptszData);
  192.  
  193.     if (put != NULL)
  194.         return put->m_ut;
  195.     else
  196.         return UT_NONE;
  197. }
  198.  
  199.  
  200.  
  201. //
  202. // Initializes the event log
  203. //
  204.  
  205. BOOL
  206. InitEventLog()
  207. {
  208.     HKEY hk = NULL; 
  209.     
  210.     // Add the source name as a subkey under the Application 
  211.     // key in the EventLog service portion of the registry. 
  212.     
  213.     if (RegCreateKey(HKEY_LOCAL_MACHINE, 
  214.                      "SYSTEM\\CurrentControlSet\\Services"
  215.                      "\\EventLog\\Application\\" EVENT_SOURCE, 
  216.                      &hk)) 
  217.     {
  218.         TRACE("could not create registry key\n"); 
  219.         return FALSE;
  220.     }
  221.  
  222.     // Get the full path of this DLL
  223.  
  224.     HMODULE hMod = GetModuleHandle(EVENT_MODULE);
  225.  
  226.     if (hMod == NULL)
  227.     {
  228.         TRACE("Can't get module handle for %s, error %d\n",
  229.               EVENT_MODULE, GetLastError());
  230.         return FALSE;
  231.     }
  232.  
  233.     CHAR szModule[MAX_PATH]; 
  234.  
  235.     if (GetModuleFileName(hMod, szModule, MAX_PATH) > 0)
  236.         TRACE("Module is `%s'\n", szModule);
  237.     else
  238.     {
  239.         TRACE("No module, error %d\n", GetLastError());
  240.         return FALSE;
  241.     }
  242.  
  243.     // Add the Event ID message-file name to the subkey.
  244.  
  245.     if (RegSetValueEx(hk,                       // subkey handle
  246.                       "EventMessageFile",       // value name
  247.                       0,                        // reserved: must be zero
  248.                       REG_EXPAND_SZ,            // value type
  249.                       (LPBYTE) szModule,        // address of value data
  250.                       strlen(szModule) + 1))    // length of value data
  251.     {
  252.         TRACE("could not set EventMessageFile\n"); 
  253.         return FALSE;
  254.     }
  255.  
  256.     // Set the supported types flags.
  257.  
  258.     DWORD dwData = (EVENTLOG_ERROR_TYPE
  259.                     | EVENTLOG_WARNING_TYPE
  260.                     | EVENTLOG_INFORMATION_TYPE); 
  261.  
  262.     if (RegSetValueEx(hk,                // subkey handle
  263.                       "TypesSupported",  // value name
  264.                       0,                 // reserved: must be zero
  265.                       REG_DWORD,         // value type
  266.                       (LPBYTE) &dwData,  // address of value data
  267.                       sizeof(dwData)))   // length of value data
  268.     {
  269.         TRACE("could not set TypesSupported\n"); 
  270.         return FALSE;
  271.     }
  272.  
  273.     RegCloseKey(hk); 
  274.  
  275.     return TRUE;
  276. }
  277.  
  278.  
  279.  
  280. //
  281. // Report things in the Event Log
  282. //
  283.  
  284. VOID
  285. EventReport(
  286.     LPCTSTR string1,
  287.     LPCTSTR string2,
  288.     WORD eventType,
  289.     DWORD eventID)
  290. {
  291.     HANDLE hEvent;
  292.     LPCTSTR pszaStrings[2];
  293.     WORD cStrings;
  294.  
  295.     cStrings = 0;
  296.     if ((pszaStrings[0] = string1) && (string1[0]))
  297.         cStrings++;
  298.     if ((pszaStrings[1] = string2) && (string2[0]))
  299.         cStrings++;
  300.     
  301.     hEvent = RegisterEventSource(NULL, EVENT_SOURCE);
  302.  
  303.     if (hEvent) 
  304.     {
  305.         ReportEvent(hEvent,         // handle returned by RegisterEventSource 
  306.                     eventType,      // event type to log 
  307.                     0,              // event category 
  308.                     eventID,        // event identifier 
  309.                     NULL,           // user security identifier (optional) 
  310.                     cStrings,       // number of strings to merge with message 
  311.                     0,              // size of binary data, in bytes
  312.                     pszaStrings,    // array of strings to merge with message 
  313.                     NULL);          // address of binary data 
  314.         DeregisterEventSource(hEvent);
  315.     }
  316. }
  317.  
  318.  
  319.  
  320. //
  321. // stristr (stolen from fts.c, wickn)
  322. //
  323. // case-insensitive version of strstr
  324. // stristr returns a pointer to the first occurrence of string2 in string1.
  325. // The search does not include terminating nul characters.
  326. //
  327.  
  328. char*
  329. stristr(const char* string1, const char* string2)
  330. {
  331.     char *cp1 = (char*) string1, *cp2, *cp1a;
  332.     char first;
  333.  
  334.     // get the first char in string to find
  335.     first = string2[0];
  336.  
  337.     // first char often won't be alpha
  338.     if (isalpha(first))
  339.     {
  340.         first = tolower(first);
  341.         for ( ; *cp1  != '\0'; cp1++)
  342.         {
  343.             if (tolower(*cp1) == first)
  344.             {
  345.                 for (cp1a = &cp1[1], cp2 = (char*) &string2[1];
  346.                      ;
  347.                      cp1a++, cp2++)
  348.                 {
  349.                     if (*cp2 == '\0')
  350.                         return cp1;
  351.                     if (tolower(*cp1a) != tolower(*cp2))
  352.                         break;
  353.                 }
  354.             }
  355.         }
  356.     }
  357.     else
  358.     {
  359.         for ( ; *cp1 != '\0' ; cp1++)
  360.         {
  361.             if (*cp1 == first)
  362.             {
  363.                 for (cp1a = &cp1[1], cp2 = (char*) &string2[1];
  364.                      ;
  365.                      cp1a++, cp2++)
  366.                 {
  367.                     if (*cp2 == '\0')
  368.                         return cp1;
  369.                     if (tolower(*cp1a) != tolower(*cp2))
  370.                         break;
  371.                 }
  372.             }
  373.         }
  374.     }
  375.  
  376.     return NULL;
  377. }
  378.  
  379.  
  380.  
  381. //
  382. // Find a string in a block of rawdata (a sort of stristr).
  383. // Can't use stristr because the rawdata is not \0-terminated.
  384. //
  385.  
  386. LPSTR
  387. FindString(
  388.     LPCSTR psz,
  389.     PHTTP_FILTER_RAW_DATA pRawData,
  390.     int iStart)
  391. {
  392.     LPSTR pszData = iStart + (LPSTR) pRawData->pvInData;
  393.     const int cch = strlen(psz);
  394.     const CHAR ch = tolower(*psz);
  395.  
  396.     for (int i = pRawData->cbInData - cch + 1 - iStart;  --i >= 0; )
  397.     {
  398.         if (ch == tolower(*pszData)  &&  strnicmp(psz, pszData, cch) == 0)
  399.             return pszData;
  400.         else
  401.             ++pszData;
  402.     }
  403.  
  404.     return NULL;
  405. }
  406.  
  407.  
  408.  
  409. //
  410. // Find a header-value pair, such as ("Content-Type:", "text/html").  Works
  411. // no matter how many spaces between the pair
  412. //
  413.  
  414. LPSTR
  415. FindHeaderValue(
  416.     LPCSTR pszHeader,
  417.     LPCSTR pszValue,
  418.     PHTTP_FILTER_RAW_DATA pRawData,
  419.     int iStart)
  420. {
  421.     LPSTR psz = FindString(pszHeader, pRawData, iStart);
  422.  
  423.     if (psz != NULL)
  424.     {
  425.         LPSTR pszData = iStart + (LPSTR) pRawData->pvInData;
  426.         int   i       = (psz - pszData) + strlen(pszHeader);
  427.         
  428.         // Skip spaces
  429.         while (i < pRawData->cbInData  &&  isspace(pszData[i]))
  430.             ++i;
  431.         
  432.         // Check for szValue
  433.         const int cchValue = strlen(pszValue);
  434.         
  435.         if (i + cchValue <= pRawData->cbInData)
  436.             if (strnicmp(pszData+i, pszValue, cchValue) == 0)
  437.                 return psz;
  438.     }
  439.  
  440.     return NULL;
  441. }
  442.  
  443.  
  444.  
  445. //
  446. // Delete a line such as "Content-Length: 924\r\n"
  447. //
  448.  
  449. BOOL
  450. DeleteLine(
  451.     LPCSTR psz,
  452.     PHTTP_FILTER_RAW_DATA pRawData,
  453.     LPSTR  pszStart /* = NULL */)
  454. {
  455.     if (pszStart == NULL)
  456.         pszStart = FindString(psz, pRawData, 0);
  457.  
  458.     if (pszStart == NULL)
  459.         return FALSE;
  460.  
  461.     LPCSTR pszData = (LPCSTR) pRawData->pvInData;
  462.  
  463.     for (unsigned i = pszStart - pszData;  i < pRawData->cbInData; )
  464.     {
  465.         if (pszData[i++] == '\n')
  466.         {
  467.             for (unsigned j = 0;  j <  pRawData->cbInData - i;  j++)
  468.                 pszStart[j] = pszData[i + j];
  469.             if (j <  pRawData->cbInData)
  470.                 pszStart[j] = '\0';
  471.             pRawData->cbInData -= i - (pszStart - pszData);
  472.  
  473.             return TRUE;
  474.         }
  475.     }
  476.  
  477.     return FALSE;
  478. }
  479.  
  480.  
  481.  
  482. //
  483. // Extract a Session ID from a Cookie header.  Cookie will be in the form
  484. //     name1=value1; name2=value2; name3=value3; ...
  485. // One of those name-value pairs should be something like:
  486. //     ASPSESSIONIDXXXXXXXX=PVZQGHUMEAYAHMFV or
  487. //     ASPSESSIONID=PVZQGHUMEAYAHMFV
  488. //
  489.  
  490. BOOL
  491. Cookie2SessionID(
  492.     LPCSTR pszCookie,
  493.     LPSTR  pszSessionID)
  494. {
  495.     if (pszCookie == NULL)
  496.     {
  497.         ASSERT(FALSE);
  498.         return FALSE;
  499.     }
  500.     
  501.     LPCSTR psz = strstr(pszCookie, SZ_SESSION_ID_COOKIE_NAME);
  502.  
  503.     if (psz == NULL)
  504.     {
  505.         TRACE("C2SID: failed strstr `%s'\n", pszCookie);
  506.         return FALSE;
  507.     }
  508.  
  509.     // skip over the "ASPSESSIONIDXXXXXXXX=" or "ASPSESSIONID=" part
  510.     psz += SZ_SESSION_ID_COOKIE_NAME_SIZE;
  511.     if (*(psz) != '=')
  512.     {
  513.         if ( strncmp( psz, g_szCookieExtra, COOKIE_NAME_EXTRA_SIZE ) == 0 )
  514.         {
  515.             psz += COOKIE_NAME_EXTRA_SIZE;
  516.             if ( *(psz) != '=' )
  517.             {
  518.                 TRACE("C2SID: no = `%s'\n", psz);
  519.                 return FALSE;
  520.             }
  521.         }
  522.         else
  523.         {
  524.             TRACE("C2SID: strncmp(%s) `%s'\n", g_szCookieExtra, psz);
  525.             return FALSE;
  526.         }
  527.     }
  528.     psz++;
  529.  
  530.     return CopySessionID(psz, pszSessionID);
  531. }
  532.  
  533.  
  534.  
  535. //
  536. // Extract a Session ID from psz, placing it into pszSessionID
  537. //
  538.  
  539. BOOL
  540. CopySessionID(
  541.     LPCSTR psz,
  542.     LPSTR  pszSessionID)
  543. {
  544.     ASSERT( g_SessionIDSize != -1 );
  545.  
  546.     strncpy(pszSessionID, psz, g_SessionIDSize);
  547.     pszSessionID[g_SessionIDSize] = '\0';
  548.  
  549. #ifdef _DEBUG
  550.     TRACE("SessionID='%s'\n", pszSessionID);
  551.     for (psz = pszSessionID;  *psz;  ++psz)
  552.         ASSERT('A' <= *psz  &&  *psz <= 'Z');
  553. #endif
  554.  
  555.     return TRUE;
  556. }
  557.  
  558.  
  559.  
  560. //
  561. // Remove an encoded Session ID from a URL, returning the Session ID 
  562. // e.g., /foo/bar.asp-ASP=PVZQGHUMEAYAHMFV?quux=5 ->
  563. //           /foo/bar.asp?quux=5 + PVZQGHUMEAYAHMFV
  564. //
  565.  
  566. BOOL
  567. DecodeURL(
  568.     LPSTR pszUrl,
  569.     LPSTR pszSessionID)
  570. {
  571.     ASSERT( g_SessionIDSize != -1 );
  572.  
  573.     TRACE("Decode(%s)", pszUrl);
  574.     
  575.     LPSTR pszQuery = strchr(pszUrl, '?');
  576.  
  577.     if (pszQuery != NULL)
  578.         *pszQuery++ = '\0';
  579.  
  580.     LPSTR pszLastSlash = strrchr(pszUrl, *SESSION_ID_PREFIX);
  581.  
  582.     if (pszLastSlash == NULL)
  583.     {
  584.         TRACE(" (no `" SESSION_ID_PREFIX "')\n");
  585.         return FALSE;
  586.     }
  587.  
  588.     const int cchEncodedID = strlen(pszLastSlash);
  589.  
  590.     if (strncmp(pszLastSlash, SESSION_ID_PREFIX, SESSION_ID_PREFIX_SIZE) != 0
  591.         || cchEncodedID !=
  592.             (SESSION_ID_PREFIX_SIZE + g_SessionIDSize + SESSION_ID_SUFFIX_SIZE)
  593.         || strcmp(pszLastSlash + cchEncodedID - SESSION_ID_SUFFIX_SIZE,
  594.                   SESSION_ID_SUFFIX) != 0)
  595.     {
  596.         if (pszQuery != NULL)
  597.             *pszQuery = '?';
  598.         TRACE(": not encoded\n");
  599.         return FALSE;
  600.     }
  601.     else
  602.     {
  603.         strncpy(pszSessionID, pszLastSlash + SESSION_ID_PREFIX_SIZE,
  604.                 g_SessionIDSize);
  605.         pszSessionID[g_SessionIDSize] = '\0';
  606.  
  607.         *pszLastSlash = '\0';
  608.  
  609.         if (pszQuery != NULL)
  610.         {
  611.             *pszLastSlash++ = '?';
  612.  
  613.             while ((*pszLastSlash++ = *pszQuery++) != '\0')
  614.                 ;
  615.         }
  616.  
  617.         TRACE(" -> %s, %s\n", pszUrl, pszSessionID);
  618.  
  619.         return TRUE;
  620.     }
  621. }
  622.  
  623.  
  624.  
  625. //
  626. // Wrapper for pfc->AllocMem.
  627. //
  628.  
  629. VOID*
  630. AllocMem(
  631.     PHTTP_FILTER_CONTEXT  pfc,
  632.     DWORD                 cbSize)
  633. {
  634.     PVOID pv = pfc->AllocMem(pfc, cbSize, 0);
  635. #ifdef _DEBUG
  636.     memset(pv, 0, cbSize);
  637. #endif
  638.     TRACE("Allocated %d (%x) bytes at %x\n", cbSize, cbSize, pv);
  639.     return pv;
  640. }
  641.