HttpClient.cpp
上传用户:dengkfang
上传日期:2008-12-30
资源大小:5233k
文件大小:65k
源码类别:

CA认证

开发平台:

Visual C++

  1. /*
  2. Module : HttpClient.cpp
  3. Purpose: Implementation for the CHttpClient class
  4. Created: PJN / 22-04-1999
  5. History: None
  6. Copyright (c) 1999 - 2005 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)
  7. All rights reserved.
  8. Copyright / Usage Details:
  9. You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
  10. when your product is released in binary form. You are allowed to modify the source code in any way you want 
  11. except you cannot modify the copyright details at the top of each module. If you want to distribute source 
  12. code with your application, then you are only allowed to distribute versions released by the author. This is 
  13. to maintain a single distribution point for the source code. 
  14. */
  15. //////////////// Includes ////////////////////////////////////////////
  16. #include "stdafx.h"
  17. #ifndef __AFXPRIV_H__
  18. #pragma message("To avoid this message please put afxpriv.h in your PCH (normally stdafx.h)")
  19. #include <afxpriv.h>
  20. #endif
  21. #include "W3Mfc.h"
  22. #include "HttpResponseHeader.h"
  23. #include "Base64.h"
  24. #include "HttpClient.h"
  25. #include "Win32Handle.h"
  26. //////////////// Macros / Defines ////////////////////////////////////
  27. #ifndef RT_HTML
  28. #define RT_HTML         MAKEINTRESOURCE(23)
  29. #endif
  30. #ifndef SEC_E_OK
  31. #define SEC_E_OK                         ((SECURITY_STATUS)0x0000)
  32. #endif
  33. #ifndef SEC_I_CONTINUE_NEEDED
  34. #define SEC_I_CONTINUE_NEEDED            ((SECURITY_STATUS)0x1012)
  35. #endif
  36. #ifndef INVALID_FILE_ATTRIBUTES
  37. #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
  38. #endif
  39. #ifndef HSE_REQ_CLOSE_CONNECTION
  40. #define HSE_REQ_CLOSE_CONNECTION                 (HSE_REQ_END_RESERVED+17)
  41. #endif
  42. #ifdef _DEBUG
  43. #define new DEBUG_NEW
  44. #undef THIS_FILE
  45. static char THIS_FILE[] = __FILE__;
  46. #endif
  47. //The local variable which handle the function pointers
  48. _W3MFC_DATA _W3MFCData;
  49. //////////////// Implementation //////////////////////////////////////
  50. _W3MFC_DATA::_W3MFC_DATA()
  51. {
  52.   //Initialize the function pointers to sane defaults
  53.   m_lpfnTransmitFile = NULL;
  54.   m_lpfnTransmitPackets = NULL;
  55.   //Only use the TransmitFile and TransmitPacket API's if we are running on 2000/XP/.NET Server
  56.   OSVERSIONINFO osvi;
  57.   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  58.   BOOL bNT = (GetVersionEx(&osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
  59.   if (bNT && (osvi.dwMajorVersion > 4))
  60.   {
  61.     m_hMSWsock = LoadLibrary(_T("MSWSOCK.DLL"));
  62.     if (m_hMSWsock)
  63.     {
  64.       m_lpfnTransmitFile = (LPTRANSMITFILE) GetProcAddress(m_hMSWsock, "TransmitFile");
  65.       m_lpfnTransmitPackets = (LPTRANSMITPACKETS) GetProcAddress(m_hMSWsock, "TransmitPackets");
  66.     }
  67.   }
  68. }
  69. _W3MFC_DATA::~_W3MFC_DATA()
  70. {
  71.   if (m_hMSWsock)
  72.   {
  73.     FreeLibrary(m_hMSWsock);
  74.     m_hMSWsock = NULL;
  75.   }
  76. }
  77. #ifndef W3MFC_NO_ISAPI_SUPPORT
  78. BOOL _W3MFC_DATA::TransmitFile(CHttpSocket& socket, CHttpResponseHeader& responseHdr, HSE_TF_INFO* pInfo)
  79. {
  80.   //Assume the worst
  81.   BOOL bSuccess = FALSE;
  82.   if (pInfo->pfnHseIO)
  83.   {
  84.     SetLastError(ERROR_INVALID_PARAMETER); //we do not support ascynchronous notifications
  85.     return FALSE;
  86.   }
  87.   if (pInfo->Offset)
  88.   {
  89.     SetLastError(ERROR_INVALID_PARAMETER); //we do not support partials sens thro TransmitFile because that requires overlapped IO
  90.     return FALSE;
  91.   }
  92.   if (pInfo->dwFlags & HSE_IO_SEND_HEADERS)
  93.   {
  94.     if (m_lpfnTransmitPackets && m_lpfnTransmitFile)
  95.     {
  96.       TRANSMIT_PACKETS_ELEMENT tpe[2];
  97.       tpe[0].pBuffer = (void*) pInfo->pszStatusCode;
  98.       tpe[0].dwElFlags = TP_ELEMENT_MEMORY;
  99.       tpe[0].cLength = strlen(pInfo->pszStatusCode);
  100.       tpe[1].pBuffer = responseHdr.GetData(tpe[1].cLength);
  101.       tpe[1].dwElFlags = TP_ELEMENT_MEMORY;
  102.       //Call the TransmitPackets function
  103.       bSuccess = m_lpfnTransmitPackets(socket, tpe, 2, 0, NULL, TF_USE_KERNEL_APC);
  104.       //And the TransmitFile function
  105.       if (bSuccess)
  106.         bSuccess = m_lpfnTransmitFile(socket, pInfo->hFile, pInfo->BytesToWrite, 0, NULL, NULL, TF_USE_KERNEL_APC);
  107.     }
  108.     else
  109.       SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  110.   }
  111.   else
  112.   {
  113.     if (m_lpfnTransmitFile)
  114.     {
  115.       TRANSMIT_FILE_BUFFERS tfb;
  116.       tfb.Head = pInfo->pHead;
  117.       tfb.HeadLength = pInfo->HeadLength;
  118.       tfb.Tail = pInfo->pTail;
  119.       tfb.TailLength = pInfo->TailLength;
  120.       //Call the TransmitFile function
  121.       bSuccess = m_lpfnTransmitFile(socket, pInfo->hFile, pInfo->BytesToWrite, 0, NULL, &tfb, TF_USE_KERNEL_APC);
  122.     }
  123.     else
  124.       SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  125.   }
  126.   return bSuccess;
  127. }
  128. #endif
  129. BOOL _W3MFC_DATA::TransmitFile(CHttpSocket& socket, CHttpResponseHeader& responseHdr, HANDLE hFile, DWORD dwSize)
  130. {
  131.   ASSERT(m_lpfnTransmitFile);
  132.   //Setup the TFB ready for the call to the "TransmitFile" function
  133.   TRANSMIT_FILE_BUFFERS tfb;
  134.   tfb.Head = responseHdr.GetData(tfb.HeadLength);
  135.   tfb.Tail = NULL;
  136.   tfb.TailLength = 0;
  137.   //Call the TransmitFile function
  138.   BOOL bSuccess = m_lpfnTransmitFile(socket, hFile, dwSize, 0, NULL, &tfb, TF_USE_KERNEL_APC);
  139.   //Tidy up the heap memory we have used
  140.   delete [] tfb.Head;
  141.   return bSuccess;
  142. }
  143. BOOL _W3MFC_DATA::TransmitBuffer(CHttpSocket& socket, CHttpResponseHeader& responseHdr, BYTE* byData, DWORD dwSize)
  144. {
  145.   ASSERT(m_lpfnTransmitPackets);
  146.   //Setup the TFB ready for the call to the "TransmitPackets" function
  147.   TRANSMIT_PACKETS_ELEMENT tpe[2];
  148.   tpe[0].pBuffer = responseHdr.GetData(tpe[0].cLength);
  149.   tpe[0].dwElFlags = TP_ELEMENT_MEMORY;
  150.   tpe[1].pBuffer = byData;
  151.   tpe[1].cLength = dwSize;
  152.   tpe[0].dwElFlags = TP_ELEMENT_MEMORY;
  153.   //Call the TransmitPackets function
  154.   return m_lpfnTransmitPackets(socket, tpe, 2, 0, NULL, TF_USE_KERNEL_APC);
  155. }
  156. IMPLEMENT_DYNCREATE(CHttpClient, CThreadPoolClient)
  157. CHttpClient::CHttpClient()
  158. {
  159.   m_pServer = NULL;
  160. #ifdef W3MFC_SSL_SUPPORT
  161.   m_pSSLContext = NULL;
  162. #endif
  163. #ifndef W3MFC_NO_ISAPI_SUPPORT
  164.   m_dwDataSentViaWriteClient = 0;
  165.   m_nHttpStatusCodeSent = 0;
  166. #endif
  167. }
  168. CHttpClient::~CHttpClient()
  169. {
  170. }
  171. BOOL CHttpClient::AllowThisConnection()
  172. {
  173.   return TRUE;
  174. }
  175. #ifdef W3MFC_SSL_SUPPORT
  176. BOOL CHttpClient::InitializeSSLConnection()
  177. {
  178.   SSL* pSSL = SSL_new(m_pSSLContext->operator SSL_CTX*());
  179.   if (pSSL == NULL)
  180.   {
  181.     //Report the error
  182.     CString sError;
  183.     sError.Format(_T("CHttpClient::InitializeSSLConnection, Failed to create create SSL connection object"));
  184.     ASSERT(m_pServer);
  185.     m_pServer->OnError(sError);
  186.     m_pServer->LogSSLErrors();
  187.     return FALSE;
  188.   }
  189.   else
  190.     m_SSL.Attach(pSSL);
  191.   //Associate the raw socket with the SSL connection object
  192.   if (SSL_set_fd(m_SSL, m_Socket) != 1)
  193.   {
  194.     //Report the error
  195.     CString sError;
  196.     sError.Format(_T("CHttpClient::InitializeSSLConnection, Failed to create create SSL connection object"));
  197.     ASSERT(m_pServer);
  198.     m_pServer->OnError(sError);
  199.     m_pServer->LogSSLErrors();
  200.     return FALSE;
  201.   }
  202.   return TRUE;
  203. }
  204. BOOL CHttpClient::DoSSLNegotiation()
  205. {
  206.   ASSERT(m_pServer);
  207.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  208.   ASSERT(pSettings);
  209.   BOOL bNegotiationComplete = FALSE;
  210.   while (!bNegotiationComplete)
  211.   {
  212.     int nSSLAccept = SSL_accept(m_SSL);
  213.     if (nSSLAccept != 1)
  214.     {
  215.       BOOL bRetry = FALSE;
  216.       int nSSL_get_error = SSL_get_error(m_SSL, nSSLAccept);
  217.       if (nSSL_get_error == SSL_ERROR_WANT_READ)
  218.       {
  219.         if (m_Socket.IsReadible(pSettings->m_dwSSLNegotiationTimeout))
  220.           bRetry = TRUE;
  221.       }
  222.       if (!bRetry)
  223.       {
  224.         //Report the error
  225.         CString sError;
  226.         sError.Format(_T("CHttpClient::DoSSLNegotiation, Failed to perform SSL handshake, SSL_accept:%d SSL_get_error:%d"), nSSLAccept, nSSL_get_error);
  227.         m_pServer->OnError(sError);
  228.         m_pServer->LogSSLErrors();
  229.         return FALSE;
  230.       }
  231.     }
  232.     else
  233.       bNegotiationComplete = TRUE;
  234.   }
  235.   return TRUE;
  236. }
  237. #endif
  238. BOOL CHttpClient::Run(const CThreadPoolRequest& request)
  239. {
  240.   //Validate our parameters
  241.   ASSERT(request.m_pData);
  242.   CHttpThreadPoolRequest* pHttpRequest = (CHttpThreadPoolRequest*) request.m_pData;
  243.   //Hive away the parameters in member variables
  244.   SOCKET clientSocket = pHttpRequest->m_ClientSocket.Detach();
  245.   m_Socket.Attach(clientSocket);
  246.   CopyMemory(&m_Request.m_ClientAddress, &pHttpRequest->m_ClientAddress, sizeof(sockaddr_in));
  247. #ifdef W3MFC_SSL_SUPPORT
  248.   m_pSSLContext = pHttpRequest->m_pSSLContext;
  249. #endif
  250.   //Call the helper function which does all of the work
  251.   HandleClient();
  252. #ifdef W3MFC_SSL_SUPPORT
  253.   //Close the SSL connection
  254.   m_SSL.Close();
  255. #endif
  256.   //Close down the connection
  257.   m_Socket.Close();
  258.   //Tidy up our heap memory after ourselves
  259.   delete pHttpRequest;
  260.   //Reset the request data
  261.   m_Request = CHttpRequest();
  262.   return TRUE;
  263. }
  264. int CHttpClient::ExitInstance()
  265. {
  266.   //Tidy up per thread SSL structures if we are using SSL
  267. #ifdef W3MFC_SSL_SUPPORT
  268.   ERR_remove_state(0);
  269. #endif
  270.   return CThreadPoolClient::ExitInstance();
  271. }
  272. void CHttpClient::HandleClient()
  273. {
  274. //Validate our parameters
  275. ASSERT(m_pServer);
  276. CHttpServerSettings* pSettings = m_pServer->GetSettings();
  277. ASSERT(pSettings);
  278. //Do the reverse DNS lookup if configured to do so
  279. m_Request.m_sRemoteHost.Empty();
  280. if (pSettings->m_bDNSLookup)
  281. {
  282. HOSTENT* pHostEnt = gethostbyaddr((const char*) &m_Request.m_ClientAddress.sin_addr, sizeof(IN_ADDR), AF_INET);
  283. if (pHostEnt)
  284. m_Request.m_sRemoteHost = pHostEnt->h_name;
  285. }
  286. //Should we allow this client to connect
  287. if (!AllowThisConnection())
  288. {
  289. ReturnErrorMessage(400); //Bad Request
  290. return;    
  291. }
  292. //Create the SSL connection if required
  293. #ifdef W3MFC_SSL_SUPPORT
  294. if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  295. {
  296. if (!InitializeSSLConnection())
  297. return;
  298. //Do the SSL negotiation
  299. if (!DoSSLNegotiation())
  300. return;
  301. }
  302. #endif
  303. //Use a Win32 event notification on the socket
  304. CEvent dataEvent;
  305. int nError = WSAEventSelect(m_Socket, dataEvent, FD_READ | FD_CLOSE);
  306. if (nError == SOCKET_ERROR)
  307. {
  308. DWORD dwError = ::GetLastError();
  309. //Report the error
  310. CString sError;
  311. sError.Format(_T("CHttpClient::HandleClient, Failed in call to WSAEventSelect, GetLastError:%d"), dwError);
  312. m_pServer->OnError(sError);
  313. return;
  314. }
  315. //Also create a waitable timer if we can
  316. CWaitableTimer dataTimer;
  317. if (dataTimer.Create(TRUE))
  318. dataTimer.SetOnceOffRelative(pSettings->m_dwIdleClientTimeout);
  319. BOOL bMoreRequests = FALSE;
  320. #ifndef W3MFC_NO_SSPI_SUPPORT
  321. BOOL bImpersonatedUsingSSPI = FALSE;
  322. #endif
  323. do
  324. {
  325. m_bResponseKeepAlive = FALSE;
  326. #ifdef W3MFC_SSL_SUPPORT
  327. //Read the client request
  328. BOOL bReadResponse = FALSE;
  329. if (dataTimer)
  330. bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, m_SSL, *this, dataTimer, m_StopEvent, dataEvent);
  331. else
  332. bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, m_SSL, *this);
  333. #else
  334. BOOL bReadResponse = FALSE;
  335. if (dataTimer)
  336. bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, *this, dataTimer, m_StopEvent, dataEvent);
  337. else
  338. bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, *this);
  339. #endif
  340. if (bReadResponse)
  341. {
  342. //Parse the client request
  343. if (ParseRequest())
  344. {
  345. m_bResponseKeepAlive = pSettings->m_bKeepAlives && m_Request.m_bKeepAlive;
  346. //Impersonate the client credentials if authorization type is PLAINTEXT
  347. CW32Handle hImpersonation;
  348. BOOL bLoggedOn = FALSE;
  349. if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_PLAINTEXT && pSettings->m_bPerformPassthroughAuthentication)
  350. {
  351. LPTSTR pszUser = m_Request.m_sUsername.GetBuffer(m_Request.m_sUsername.GetLength());
  352. LPTSTR pszPassword = m_Request.m_sPassword.GetBuffer(m_Request.m_sPassword.GetLength());
  353. bLoggedOn = LogonUser(pszUser, NULL, pszPassword, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hImpersonation);
  354. if (bLoggedOn)
  355. {
  356. ImpersonateLoggedOnUser(hImpersonation);
  357. m_Request.m_bLoggedOn = TRUE;
  358. }
  359. else
  360. {
  361. //Report the error
  362. CString sError;
  363. sError.Format(_T("CHttpClient::HandleClient, Failed to logon using user name: %s, GetLastError:%d"), pszUser, ::GetLastError());
  364. m_pServer->OnError(sError);
  365. }
  366. m_Request.m_sUsername.ReleaseBuffer();
  367. m_Request.m_sPassword.ReleaseBuffer();
  368. #ifndef W3MFC_NO_SSPI_SUPPORT
  369. else if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_NTLM && !bImpersonatedUsingSSPI)
  370. {
  371. bImpersonatedUsingSSPI = TRUE;
  372. SECURITY_STATUS ss = ImpersonateSecurityContext(&m_Request.m_ContentHandle);
  373. bLoggedOn = (ss == SEC_E_OK);
  374. if (bLoggedOn)
  375. {
  376. //Pull out some values from the SSPI context handle and stuff them in the request object
  377. SecPkgContext_Names names;
  378. if (QueryContextAttributes(&m_Request.m_ContentHandle, SECPKG_ATTR_NAMES, &names) == SEC_E_OK)
  379. {
  380. m_Request.m_sUsername = names.sUserName;
  381. FreeContextBuffer(names.sUserName);
  382. }
  383. SecPkgContext_Authority authority;
  384. if (QueryContextAttributes(&m_Request.m_ContentHandle, SECPKG_ATTR_AUTHORITY, &authority) == SEC_E_OK)
  385. {
  386. m_Request.m_sAuthorityName = authority.sAuthorityName;
  387. FreeContextBuffer(authority.sAuthorityName);
  388. }
  389. }
  390. else
  391. {
  392. //Report the error
  393. CString sError;
  394. sError.Format(_T("CHttpClient::HandleClient, Failed to impersonate client credentials using SSPI: %s, Error:%d"), ss);
  395. m_pServer->OnError(sError);
  396. }
  397. }
  398. #endif
  399. m_Request.m_hImpersonation = hImpersonation;
  400. if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_ANONYMOUS && !pSettings->m_bAllowAnonymous)
  401. {
  402. //Return an unauthorized message if some form of authentication is enabled
  403. if (pSettings->m_bAllowBasicAuthentication || pSettings->m_bAllowNTLMAuthentication)
  404. ReturnUnauthorizedMessage(m_Request.m_sURL);
  405. else
  406. {
  407. //Report the error
  408. m_pServer->OnError(_T("CHttpClient::HandleClient, Anonymous access is disabled in addition to all authentication mechanisms, All requests will Fail!!"));
  409. ReturnErrorMessage(500); //Internal server error
  410. }
  411. }
  412. else
  413. {
  414. if (m_Request.m_Verb == CHttpRequest::HTTP_VERB_GET || m_Request.m_Verb == CHttpRequest::HTTP_VERB_HEAD || m_Request.m_Verb == CHttpRequest::HTTP_VERB_POST)
  415. {
  416. if (!PreHandleGetPostHead()) //Allow derived classes to handle GET, HEAD or POST
  417. {
  418. BOOL bDirectory = FALSE;
  419. CHttpDirectory* pDirectory = NULL;
  420. DWORD dwMatchingURL = 0;
  421. DWORD dwMatchingPath = 0;
  422. if (MapURLToLocalFilename(m_Request.m_sURL, m_Request.m_sLocalFile, m_Request.m_sPathInfo, bDirectory, pDirectory, dwMatchingURL, dwMatchingPath))
  423. {
  424. ASSERT(pDirectory);
  425. pDirectory->HandleDirectory(this, bDirectory);
  426. }
  427. else
  428. ReturnErrorMessage(404); //Not Found
  429. }
  430. }
  431. else if (pSettings->m_bAllowDeleteRequest && m_Request.m_Verb == CHttpRequest::HTTP_VERB_DELETE)
  432. {
  433. //By default, only allow deletion of a file if we are using authorization
  434. if (m_Request.m_AuthorizationType != CHttpRequest::HTTP_AUTHORIZATION_ANONYMOUS)
  435. {
  436. CString sLocalFile;
  437. BOOL bDirectory = FALSE;
  438. CHttpDirectory* pDirectory = NULL;
  439. DWORD dwMatchingURL = 0;
  440. DWORD dwMatchingPath = 0;
  441. if (MapURLToLocalFilename(m_Request.m_sURL, m_Request.m_sLocalFile, m_Request.m_sPathInfo, bDirectory, pDirectory, dwMatchingURL, dwMatchingPath) && !bDirectory && pDirectory->GetWritable())
  442. {
  443. if (DeleteFile(m_Request.m_sLocalFile))
  444. ReturnFileDeletedOkMessage(m_Request.m_sLocalFile);
  445. else
  446. {
  447. if (::GetLastError() == ERROR_ACCESS_DENIED && !bDirectory)
  448. ReturnUnauthorizedMessage(m_Request.m_sURL);
  449. else 
  450. ReturnErrorMessage(500); //Internal server error
  451. }
  452. }
  453. else
  454. ReturnErrorMessage(404); //Not Found
  455. }
  456. else if (pSettings->m_bAllowBasicAuthentication || pSettings->m_bAllowNTLMAuthentication)
  457. ReturnUnauthorizedMessage(m_Request.m_sURL); //Not authorized
  458. else
  459. ReturnErrorMessage(404); //Not Found
  460. }
  461. else
  462. ReturnErrorMessage(501); //Not implemented
  463. }
  464. //Restore our usual security priviledges
  465. if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_PLAINTEXT)
  466. {
  467. //Revert to the usual security settings
  468. RevertToSelf();
  469. }
  470.       }
  471.       else
  472.   ReturnErrorMessage(400); //Bad Request
  473.     }
  474.     //Should we service another request
  475.     bMoreRequests = m_bResponseKeepAlive;
  476.     //Remember some values from the old request
  477.     BOOL bAuthenticationCompleted = m_Request.m_bAuthenticationComplete;
  478.     CHttpRequest::HttpAuthorization Authorization = m_Request.m_AuthorizationType;
  479.     CString sRemoteHost = m_Request.m_sRemoteHost;
  480.     CString sUsername = m_Request.m_sUsername;
  481.     CString sAuthorityName = m_Request.m_sAuthorityName;
  482.     sockaddr_in clientAddress;
  483.     CopyMemory(&clientAddress, &m_Request.m_ClientAddress, sizeof(sockaddr_in));
  484.     //Reset the request data before we (potentially) loop around or exit
  485.     m_Request = CHttpRequest();
  486.     //Reinstate the Authentication completed flag. This prevents the need for reauthentications if the connection is keep alive
  487.     m_Request.m_bAuthenticationComplete = bAuthenticationCompleted;
  488.     //Reinstate the Authentication type and the Authority type and username (if it requires keep alives, which is only NTLM currently)
  489.     if (Authorization == CHttpRequest::HTTP_AUTHORIZATION_NTLM)
  490.     {
  491. m_Request.m_AuthorizationType = Authorization;
  492. m_Request.m_sUsername = sUsername;
  493. m_Request.m_sAuthorityName = sAuthorityName;
  494.     }
  495.     //Reinstate the client connection details
  496.     CopyMemory(&m_Request.m_ClientAddress, &clientAddress, sizeof(sockaddr_in));
  497.     m_Request.m_sRemoteHost = sRemoteHost;
  498.   }
  499.   while (bMoreRequests);
  500.   
  501.   //Undo the SSPI impersonation
  502. #ifndef W3MFC_NO_SSPI_SUPPORT
  503.   if (bImpersonatedUsingSSPI)
  504.   RevertSecurityContext(&m_Request.m_ContentHandle);
  505.   
  506.   //Free up the context handle
  507.   DeleteSecurityContext(&m_Request.m_ContentHandle);
  508. #endif
  509. }
  510. BOOL CHttpClient::ParseSimpleRequestLine(const CString& sLine)
  511. {
  512.   ASSERT(m_pServer);
  513.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  514.   ASSERT(pSettings);
  515.   //Make a local copy of the string for parsing purposes
  516.   TCHAR* pszLine = new TCHAR[sLine.GetLength() + 1];
  517.   _tcscpy(pszLine, sLine);
  518.   //Assume the worst
  519.   BOOL bSuccess = FALSE;
  520.   //First parse out the VERB
  521.   TCHAR seps[] = _T(" ");
  522.   TCHAR* pszVerb = _tcstok(pszLine, seps);
  523.   if (pszVerb)
  524.   {
  525.     m_Request.m_sVerb = pszVerb;
  526.     if (_tcsicmp(pszVerb, _T("GET")) == 0)
  527.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_GET;
  528.     else if (_tcsicmp(pszVerb, _T("POST")) == 0)
  529.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_POST;
  530.     else if (_tcsicmp(pszVerb, _T("HEAD")) == 0)
  531.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_HEAD;
  532.     else if (_tcsicmp(pszVerb, _T("PUT")) == 0)
  533.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_PUT;
  534.     else if (_tcsicmp(pszVerb, _T("LINK")) == 0)
  535.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_LINK;
  536.     else if (_tcsicmp(pszVerb, _T("DELETE")) == 0)
  537.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_DELETE;
  538.     else if (_tcsicmp(pszVerb, _T("UNLINK")) == 0)
  539.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_UNLINK;
  540.     else
  541.       m_Request.m_Verb = CHttpRequest::HTTP_VERB_UNKNOWN;
  542.     //Parse out the URL
  543.     TCHAR* pszURL = _tcstok(NULL, seps);
  544.     if (pszURL)
  545.     {
  546.       m_Request.m_sRawURL = pszURL;
  547.       m_Request.m_sURL = UTF8ToCString(URLDecode(pszURL)); //Convert any embedded escape sequences to their unencoded format 
  548.                                                            //as well as handling UTF8 input data
  549.       //Handle the Search path i.e everything after the ?
  550.       int nQuestion = m_Request.m_sURL.Find(_T('?'));
  551.       if (nQuestion != -1)
  552.       {
  553.         m_Request.m_sExtra = m_Request.m_sURL.Right(m_Request.m_sURL.GetLength() - nQuestion - 1);
  554.         m_Request.m_sURL = m_Request.m_sURL.Left(nQuestion);
  555.       }
  556.       nQuestion = m_Request.m_sRawURL.Find(_T('?'));
  557.       if (nQuestion != -1)
  558.         m_Request.m_sRawExtra = m_Request.m_sRawURL.Right(m_Request.m_sRawURL.GetLength() - nQuestion - 1);
  559.       //Parse out the HTTP version
  560.       TCHAR* pszVersion = _tcstok(NULL, seps);
  561.       if (pszVersion)
  562.       {
  563.         if (_tcsstr(pszVersion, _T("HTTP/")) == pszVersion)
  564.         {
  565.           TCHAR sepsVer[] = _T(".");
  566.           TCHAR* pszMajorVersion = _tcstok(pszVersion+5, sepsVer);
  567.           if (pszMajorVersion)
  568.           {
  569.             WORD wMajorVersion = (WORD) _ttoi(pszMajorVersion);
  570.             TCHAR* pszMinorVersion = _tcstok(NULL, sepsVer);
  571.             if (pszMinorVersion)
  572.             {
  573.               WORD wMinorVersion = (WORD) _ttoi(pszMinorVersion);
  574.               m_Request.m_dwHttpVersion = MAKELONG(wMinorVersion, wMajorVersion);
  575.               bSuccess = TRUE;
  576.             }
  577.           }
  578.         }
  579.       }
  580.       else
  581.       {
  582.         //No version included in the request, so set it to HTTP v0.9
  583.         m_Request.m_dwHttpVersion = MAKELONG(9, 0);
  584.         bSuccess = m_Request.m_Verb == CHttpRequest::HTTP_VERB_GET; //"GET" is only allowed with HTTP v0.9
  585.       }  
  586.     }
  587.   }
  588.   //Tidy up the heap memory we have used before we return
  589.   delete [] pszLine;
  590.   return bSuccess;
  591. }
  592. BOOL CHttpClient::ParseWeekDay(char* pszToken, int& nWeekDay)
  593. {
  594.   BOOL bSuccess = TRUE;
  595.   if (strcmpi(pszToken, "Sun") == 0 || strcmpi(pszToken, "Sunday") == 0)
  596.     nWeekDay = 0;
  597.   else if (strcmpi(pszToken, "Mon") == 0 || strcmpi(pszToken, "Monday") == 0)
  598.     nWeekDay = 1;
  599.   else if (strcmpi(pszToken, "Tue") == 0 || strcmpi(pszToken, "Tuesday") == 0)
  600.     nWeekDay = 2;
  601.   else if (strcmpi(pszToken, "Wed") == 0 || strcmpi(pszToken, "Wednesday") == 0)
  602.     nWeekDay = 3;
  603.   else if (strcmpi(pszToken, "Thu") == 0 || strcmpi(pszToken, "Thursday") == 0)
  604.     nWeekDay = 4;
  605.   else if (strcmpi(pszToken, "Fri") == 0 || strcmpi(pszToken, "Friday") == 0)
  606.     nWeekDay = 5;
  607.   else if (strcmpi(pszToken, "Sat") == 0 || strcmpi(pszToken, "Saturday") == 0)
  608.     nWeekDay = 6;
  609.   else
  610.     bSuccess = FALSE;
  611.   return bSuccess;
  612. }
  613. BOOL CHttpClient::ParseMonth(char* pszToken, int& nMonth)
  614. {
  615.   BOOL bSuccess = TRUE;
  616.   if (strcmpi(pszToken, "Jan") == 0)
  617.     nMonth = 1;
  618.   else if (strcmpi(pszToken, "Feb") == 0)
  619.     nMonth = 2;
  620.   else if (strcmpi(pszToken, "Mar") == 0)
  621.     nMonth = 3;
  622.   else if (strcmpi(pszToken, "Apr") == 0)
  623.     nMonth = 4;
  624.   else if (strcmpi(pszToken, "May") == 0)
  625.     nMonth = 5;
  626.   else if (strcmpi(pszToken, "Jun") == 0)
  627.     nMonth = 6;
  628.   else if (strcmpi(pszToken, "Jul") == 0)
  629.     nMonth = 7;
  630.   else if (strcmpi(pszToken, "Aug") == 0)
  631.     nMonth = 8;
  632.   else if (strcmpi(pszToken, "Sep") == 0)
  633.     nMonth = 9;
  634.   else if (strcmpi(pszToken, "Oct") == 0)
  635.     nMonth = 10;
  636.   else if (strcmpi(pszToken, "Nov") == 0)
  637.     nMonth = 11;
  638.   else if (strcmpi(pszToken, "Dec") == 0)
  639.     nMonth = 12;
  640.   else
  641.     bSuccess = FALSE;
  642.   return bSuccess;
  643. }
  644. BOOL CHttpClient::ParseDate(const CString& sField, SYSTEMTIME& time)
  645. {
  646.   //This method understands RFC 1123, RFC 850 and asctime formats
  647. //For correct operation of the T2A macro, see MFC Tech Note 59
  648.   USES_CONVERSION;
  649.   BOOL bSuccess = FALSE;
  650.   //Make a local copy of the field we are going to parse
  651.   char* pszField = T2A((LPTSTR) (LPCTSTR) sField);
  652.   //Http times never include a millisecond field, so just set it to zero
  653.   time.wMilliseconds = 0;
  654.   int nLength = strlen(pszField);
  655.   if (nLength > 5)
  656.   {
  657.     if (pszField[3] == ',') //Parsing a RFC 1123 format date
  658.     {
  659.       //First the weekday
  660.       char seps[] = ", :";
  661.       char* pszToken = strtok(pszField, seps);
  662.       if (pszToken == NULL)
  663.         return FALSE;
  664.       int nWeekDay;
  665.       bSuccess = ParseWeekDay(pszToken, nWeekDay);
  666.       if (bSuccess)
  667.         time.wDayOfWeek = (WORD) nWeekDay;
  668.       //Then the day of the month
  669.       pszToken = strtok(NULL, seps);
  670.       if (pszToken == NULL)
  671.         return FALSE;
  672.       time.wDay = (WORD) atoi(pszToken);
  673.       //Then the month
  674.       pszToken = strtok(NULL, seps);
  675.       if (pszToken == NULL)
  676.         return FALSE;
  677.       int nMonth = 0;
  678.       bSuccess = bSuccess && ParseMonth(pszToken, nMonth);
  679.       if (bSuccess)
  680.         time.wMonth = (WORD) nMonth;
  681.       //And the year
  682.       pszToken = strtok(NULL, seps);
  683.       if (pszToken == NULL)
  684.         return FALSE;
  685.       time.wYear = (WORD) atoi(pszToken);
  686.       //And the hour
  687.       pszToken = strtok(NULL, seps);
  688.       if (pszToken == NULL)
  689.         return FALSE;
  690.       time.wHour = (WORD) atoi(pszToken);
  691.       //And the minute
  692.       pszToken = strtok(NULL, seps);
  693.       if (pszToken == NULL)
  694.         return FALSE;
  695.       time.wMinute = (WORD) atoi(pszToken);
  696.       //And the second
  697.       pszToken = strtok(NULL, seps);
  698.       if (pszToken == NULL)
  699.         return FALSE;
  700.       time.wSecond = (WORD) atoi(pszToken);
  701.     }
  702.     else if (pszField[3] == ' ') //Parsing an asctime format date
  703.     {
  704.       //First the weekday
  705.       char seps[] = ", :";
  706.       char* pszToken = strtok(pszField, seps);
  707.       if (pszToken == NULL)
  708.         return FALSE;
  709.       int nWeekDay;
  710.       bSuccess = ParseWeekDay(pszToken, nWeekDay);
  711.       if (bSuccess)
  712.         time.wDayOfWeek = (WORD) nWeekDay;
  713.       //Then the month
  714.       pszToken = strtok(NULL, seps);
  715.       if (pszToken == NULL)
  716.         return FALSE;
  717.       int nMonth = 0;
  718.       bSuccess = bSuccess && ParseMonth(pszToken, nMonth);
  719.       if (bSuccess)
  720.         time.wMonth = (WORD) nMonth;
  721.       //Then the day of the month
  722.       pszToken = strtok(NULL, seps);
  723.       if (pszToken == NULL)
  724.         return FALSE;
  725.       time.wDay = (WORD) atoi(pszToken);
  726.       //And the hour
  727.       pszToken = strtok(NULL, seps);
  728.       if (pszToken == NULL)
  729.         return FALSE;
  730.       time.wHour = (WORD) atoi(pszToken);
  731.       //And the minute
  732.       pszToken = strtok(NULL, seps);
  733.       if (pszToken == NULL)
  734.         return FALSE;
  735.       time.wMinute = (WORD) atoi(pszToken);
  736.       //And the second
  737.       pszToken = strtok(NULL, seps);
  738.       if (pszToken == NULL)
  739.         return FALSE;
  740.       time.wSecond = (WORD) atoi(pszToken);
  741.       //And the year
  742.       pszToken = strtok(NULL, seps);
  743.       if (pszToken == NULL)
  744.         return FALSE;
  745.       time.wYear = (WORD) atoi(pszToken);
  746.     }
  747.     else //Must be a RFC 850 format date
  748.     {
  749.       //First the weekday
  750.       char seps[] = ", :-";
  751.       char* pszToken = strtok(pszField, seps);
  752.       if (pszToken == NULL)
  753.         return FALSE;
  754.       int nWeekDay;
  755.       bSuccess = ParseWeekDay(pszToken, nWeekDay);
  756.       if (bSuccess)
  757.         time.wDayOfWeek = (WORD) nWeekDay;
  758.       //Then the day of the month
  759.       pszToken = strtok(NULL, seps);
  760.       if (pszToken == NULL)
  761.         return FALSE;
  762.       time.wDay = (WORD) atoi(pszToken);
  763.       //Then the month
  764.       pszToken = strtok(NULL, seps);
  765.       if (pszToken == NULL)
  766.         return FALSE;
  767.       int nMonth = 0;
  768.       bSuccess = bSuccess && ParseMonth(pszToken, nMonth);
  769.       if (bSuccess)
  770.         time.wMonth = (WORD) nMonth;
  771.       //And the year (2 Digits only, so make some intelligent assumptions)
  772.       pszToken = strtok(NULL, seps);
  773.       if (pszToken == NULL)
  774.         return FALSE;
  775.       time.wYear = (WORD) atoi(pszToken);
  776.       if (time.wYear < 50)
  777.         time.wYear += 2000;
  778.       else if (time.wYear < 100)
  779.         time.wYear += 1900; 
  780.       //And the hour
  781.       pszToken = strtok(NULL, seps);
  782.       if (pszToken == NULL)
  783.         return FALSE;
  784.       time.wHour = (WORD) atoi(pszToken);
  785.       //And the minute
  786.       pszToken = strtok(NULL, seps);
  787.       if (pszToken == NULL)
  788.         return FALSE;
  789.       time.wMinute = (WORD) atoi(pszToken);
  790.       //And the second
  791.       pszToken = strtok(NULL, seps);
  792.       if (pszToken == NULL)
  793.         return FALSE;
  794.       time.wSecond = (WORD) atoi(pszToken);
  795.     }
  796.   }
  797.   return bSuccess;
  798. }
  799. BOOL CHttpClient::ParseAuthorizationLine(const CString& sField)
  800. {
  801.   //Validate our parameters
  802.   ASSERT(m_pServer);
  803.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  804.   ASSERT(pSettings);
  805.   //By default assume the best
  806.   BOOL bSuccess = TRUE;
  807. //For correct operation of the T2A macro, see MFC Tech Note 59
  808.   USES_CONVERSION;
  809.   //Make a local copy of the field we are going to parse
  810.   char* pszField = T2A((LPTSTR) (LPCTSTR) sField);
  811.   char seps[] = " ";
  812.   char* pszToken = strtok(pszField, seps);
  813.   if (pszToken)
  814.   {
  815.     //Parse out the base64 encoded username and password if we are doing Basic authentication
  816.     if ((strcmpi(pszToken, "Basic") == 0) && pSettings->m_bAllowBasicAuthentication)
  817.     {
  818.       //Move to the base64 encoded data after the text "Basic"
  819.       pszToken = strtok(NULL, seps);
  820.       if (pszToken)
  821.       {
  822.         //Decode the base64 string passed to us
  823.         CBase64 base64;
  824.         int nEncodedLength = strlen(pszToken);
  825.         int nDecodedLength = base64.DecodeGetRequiredLength(nEncodedLength);
  826.         BYTE* pszOutput = new BYTE[nDecodedLength + 1];
  827.         int nOutputLength = 0;
  828.         if (base64.Decode(pszToken, nEncodedLength, pszOutput, &nOutputLength))
  829.         {
  830.           //NULL terminate the decoded data
  831.           pszOutput[nOutputLength] = '';
  832.           CString sOutput(pszOutput);
  833.           int nColon = sOutput.Find(_T(":"));
  834.           if (nColon != -1)
  835.           {
  836.             m_Request.m_AuthorizationType = CHttpRequest::HTTP_AUTHORIZATION_PLAINTEXT;
  837.             m_Request.m_sUsername = sOutput.Left(nColon);
  838.             m_Request.m_sPassword = sOutput.Right(sOutput.GetLength() - nColon - 1);
  839.           }
  840.         }
  841.         else
  842.           bSuccess = FALSE;
  843.         //Tidy up the heap memory we have been using
  844.         delete [] pszOutput;
  845.       }
  846.       else
  847.         bSuccess = FALSE;
  848.     }
  849.   #ifndef W3MFC_NO_SSPI_SUPPORT
  850.     else if ((strcmpi(pszToken, "NTLM") == 0) && pSettings->m_bAllowNTLMAuthentication && !m_Request.m_bAuthenticationComplete)
  851.     {
  852.       //Move to the encoded data after the text "NTLM"
  853.       pszToken = strtok(NULL, seps);
  854.       if (pszToken)
  855.       {
  856.         CBase64 base64;
  857.         int nEncodedLength = strlen(pszToken);
  858.         int nDecodedLength = base64.DecodeGetRequiredLength(nEncodedLength);
  859.         BYTE* pszInput = new BYTE[nDecodedLength + 1];
  860.         int nInputLength = 0;
  861.         if (base64.Decode(pszToken, nEncodedLength, pszInput, &nInputLength))
  862.         {
  863.           //Get SSPI to act on the received data
  864.           //First setup the buffers
  865.           SecBuffer secBufferIn[1];
  866.           secBufferIn[0].BufferType = SECBUFFER_TOKEN;
  867.           secBufferIn[0].cbBuffer = nInputLength;
  868.           secBufferIn[0].pvBuffer = pszInput; 
  869.           SecBufferDesc secbufDescriptorIn;
  870.           secbufDescriptorIn.ulVersion = SECBUFFER_VERSION;
  871.           secbufDescriptorIn.cBuffers = 1;
  872.           secbufDescriptorIn.pBuffers = secBufferIn;
  873.           SecBuffer secBufferOut[1];
  874.           secBufferOut[0].BufferType = SECBUFFER_TOKEN;
  875.           secBufferOut[0].cbBuffer = 0;
  876.           secBufferOut[0].pvBuffer = NULL;
  877.           SecBufferDesc secbufDescriptorOut;
  878.           secbufDescriptorOut.ulVersion = SECBUFFER_VERSION;
  879.           secbufDescriptorOut.cBuffers = 1;
  880.           secbufDescriptorOut.pBuffers = secBufferOut;
  881.           //Call SSPI
  882.           ULONG nContextAttributes;
  883.           SECURITY_STATUS ss = AcceptSecurityContext(m_pServer->GetCredentialHandle(), m_Request.m_bFirstAuthenticationRequest ? NULL : &m_Request.m_ContentHandle, 
  884.                                                      &secbufDescriptorIn, ASC_REQ_STREAM | ASC_REQ_ALLOCATE_MEMORY, SECURITY_NETWORK_DREP, 
  885.                                                      &m_Request.m_ContentHandle, &secbufDescriptorOut, &nContextAttributes, NULL);
  886.           //It's no longer the first request
  887.           m_Request.m_bFirstAuthenticationRequest = FALSE;
  888.           //Seup the output data (if any)
  889.           if (secBufferOut[0].cbBuffer)
  890.           {
  891.             nEncodedLength = base64.EncodeGetRequiredLength(secBufferOut[0].cbBuffer, BASE64_FLAG_NOCRLF);
  892.             char* pszOutput = new char[nEncodedLength + 1];
  893.             //Base 64 encode the data to be sent
  894.             base64.Encode((const BYTE*) secBufferOut[0].pvBuffer, secBufferOut[0].cbBuffer, pszOutput, &nEncodedLength, BASE64_FLAG_NOCRLF);
  895.             //Null terminate the data
  896.             pszOutput[nEncodedLength] = '';
  897.             //Set the data to return to the client
  898.             m_Request.m_sAuthenticationResponse = pszOutput;
  899.             //Tidy up the heap memory we have been using
  900.             delete [] pszOutput;
  901.             //Also free the data allocated by SSPI
  902.             FreeContextBuffer(secBufferOut[0].pvBuffer);
  903.           }
  904.           //Do we need more data from the client?
  905.           m_Request.m_bAuthenticationComplete = (ss != SEC_I_CONTINUE_NEEDED);
  906.           //Is the authentication handshake completed
  907.           if (ss == SEC_E_OK)
  908.             m_Request.m_AuthorizationType = CHttpRequest::HTTP_AUTHORIZATION_NTLM;
  909.           bSuccess = (ss == SEC_E_OK || ss == SEC_I_CONTINUE_NEEDED);
  910.         }
  911.         else
  912.           bSuccess = FALSE;
  913.         //Tidy up the heap memory we have been using
  914.         delete [] pszInput;
  915.       }
  916.       else
  917.         bSuccess = FALSE;      
  918.     }
  919.   #endif //W3MFC_NO_SSPI_SUPPORT
  920.   }
  921.   return bSuccess;
  922. }
  923. BOOL CHttpClient::ParseRequestLine(const CString& sCurrentLine, BOOL bFirstLine, const CString& sField, const CString& sValue)
  924. {
  925.   //Assume the worst
  926.   BOOL bSuccess = FALSE;
  927.   if (bFirstLine)
  928.   {
  929.     //Handle the first line
  930.     m_Request.m_sRequest = sCurrentLine;
  931.     bSuccess = ParseSimpleRequestLine(sCurrentLine);
  932.   }
  933.   else
  934.   {
  935.     bSuccess = TRUE;
  936.     //Also add the header line to the header map
  937.     CString sKey(sField);
  938.     sKey.MakeUpper();
  939.     m_Request.m_HeaderMap.SetAt(sKey, sValue);
  940.     //Handle any other request headers  
  941.     if (sField.CompareNoCase(_T("If-Modified-Since")) == 0)
  942.     {
  943.       //Handle the If-Modified-Since header
  944.       SYSTEMTIME time;
  945.       if (ParseDate(sValue, time))
  946.       {
  947.         m_Request.m_bIfModifiedSincePresent = TRUE; 
  948.         CopyMemory(&m_Request.m_IfModifiedSince, &time, sizeof(SYSTEMTIME));
  949.       }
  950.     }
  951.     else if (sField.CompareNoCase(_T("Authorization")) == 0)
  952.     {
  953.       //Handle the Authorization header
  954.       bSuccess = ParseAuthorizationLine(sValue);
  955.     }
  956.     else if (sField.CompareNoCase(_T("Content-Type")) == 0)
  957.       m_Request.m_sContentType = sValue;
  958.     else if (sField.CompareNoCase(_T("Content-Length")) == 0)
  959.       m_Request.m_nContentLength = _ttoi(sValue);
  960.     else if ((sField.CompareNoCase(_T("Connection")) == 0) && (sValue.CompareNoCase(_T("Keep-Alive")) == 0))
  961.       m_Request.m_bKeepAlive = TRUE;
  962.   }
  963.   return bSuccess;
  964. }
  965. LPSTR CHttpClient::FindNextTerminatorFromRequest(LPSTR pszLine)
  966. {
  967.   LPSTR pszCurrentLine = pszLine;
  968.   while (TRUE)
  969.   {
  970.     ++pszCurrentLine;
  971.     if (pszCurrentLine >= ((LPSTR) m_Request.m_pRawEntity))
  972.       return pszCurrentLine;
  973.     else if (*pszCurrentLine == 'n')
  974.       return pszCurrentLine;
  975.   }
  976.   
  977.   return NULL;
  978. }
  979. BOOL CHttpClient::ParseRequest()
  980. {
  981.   //By default assume the worst 
  982.   BOOL bSuccess = FALSE;
  983.   //Also store a pointer to entity body.
  984.   LPSTR pszEntityTerminator = strstr((LPSTR) m_Request.m_pRawRequest, "rnrn");
  985.   if (pszEntityTerminator)
  986.   {
  987.     m_Request.m_pRawEntity = (BYTE*) (pszEntityTerminator+4);
  988.     m_Request.m_dwRawEntitySize = m_Request.m_dwRawRequestSize - (m_Request.m_pRawEntity - m_Request.m_pRawRequest);
  989.   }
  990.   else
  991.   {
  992.     m_Request.m_pRawEntity = NULL;
  993.     m_Request.m_dwRawEntitySize = 0;
  994.   }
  995.   //Process each line
  996.   BOOL bFirstLine = TRUE;
  997.   LPSTR pszLine = (LPSTR) m_Request.m_pRawRequest;
  998.   LPSTR pszTerminator = strstr(pszLine, "n");
  999.   BOOL bMoreLines = TRUE;
  1000.   do 
  1001.   {
  1002.     CString sLine;
  1003.     if (pszTerminator)
  1004.     {
  1005.       //Form the current line
  1006.       int nCurSize = pszTerminator - pszLine;
  1007.       char* pszCurrentLine = new char[nCurSize];
  1008.       strncpy(pszCurrentLine, pszLine, nCurSize-1);
  1009.       pszCurrentLine[nCurSize-1] = ''; 
  1010.       //Transfer to the CString variable
  1011.       sLine = pszCurrentLine;
  1012.       //Tidy up the heap memory now that we are finished with it
  1013.       delete [] pszCurrentLine; 
  1014.       //Parse each line using the virtual ParseRequestLine method
  1015.       if (sLine.GetLength())
  1016.       {
  1017.       CString sField;
  1018.         CString sValue;
  1019.         if (!bFirstLine)
  1020.         {
  1021.           m_Socket.SplitRequestLine(sLine, sField, sValue);
  1022.           bSuccess = ParseRequestLine(sLine, FALSE, sField, sValue);
  1023.         }
  1024.         else
  1025.         {
  1026.           bSuccess = ParseRequestLine(sLine, TRUE, sField, sValue);
  1027.           bFirstLine = FALSE;
  1028.         }
  1029.       }
  1030.       //Move onto the next line
  1031.       if (pszTerminator)
  1032.       {
  1033.         pszLine = pszTerminator+1;
  1034.         if (pszLine >= (LPSTR) m_Request.m_pRawEntity)
  1035.           bMoreLines = FALSE;
  1036.         else 
  1037.           pszTerminator = FindNextTerminatorFromRequest(pszLine);
  1038.       }
  1039.     }  
  1040.     else
  1041.       bMoreLines = FALSE;
  1042.   }
  1043.   while (bMoreLines && bSuccess);
  1044.   m_Request.m_hImpersonation = m_pServer->GetImpersonationHandle();
  1045.   return bSuccess;
  1046. }
  1047. DWORD CHttpClient::ReturnErrorMessage(int nStatusCode)
  1048. {
  1049.   //Validate our parameters
  1050.   ASSERT(m_pServer);
  1051.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1052.   ASSERT(pSettings);
  1053.   //Form the body of the response
  1054.   DWORD dwBodyLength = 0;
  1055.   char* pszBody = m_pServer->LoadHTML(nStatusCode, dwBodyLength);
  1056.   if (m_Request.m_dwHttpVersion > MAKELONG(9, 0))
  1057.   {
  1058.     //Form the header of the response
  1059.     CHttpResponseHeader responseHdr;
  1060.     responseHdr.AddStatusCode(nStatusCode);
  1061.     SYSTEMTIME st;
  1062.     GetSystemTime(&st);
  1063.     responseHdr.AddDate(st);
  1064.     responseHdr.AddServer(pSettings->m_sServerName);
  1065.     responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
  1066.     if (m_bResponseKeepAlive)
  1067.       responseHdr.AddKeepAlive();
  1068.     responseHdr.AddContentLength(dwBodyLength);
  1069.     responseHdr.AddContentType(_T("text/html"));
  1070.     //Send the header and body all in one
  1071.     TransmitBuffer(m_Socket, responseHdr, (BYTE*)pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
  1072.   }
  1073.   else
  1074.   {
  1075.     //No header sent for HTTP v0.9
  1076.     //so just send the body
  1077.     try
  1078.     {
  1079. #ifdef W3MFC_SSL_SUPPORT
  1080.       m_Socket.SendWithRetry(pszBody, dwBodyLength, pSettings->m_dwWritableTimeout, m_SSL);
  1081. #else    
  1082.       m_Socket.SendWithRetry(pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
  1083. #endif
  1084.     }
  1085.     catch(CWSocketException* pEx)
  1086.     {
  1087.       //Report the error
  1088.       CString sError;
  1089.       sError.Format(_T("CHttpClient::ReturnErrorMessage, Failed to send to socket, Error:%d"), pEx->m_nError);
  1090.       ASSERT(m_pServer);
  1091.       m_pServer->OnError(sError);
  1092.       pEx->Delete();  
  1093.     }
  1094.   }
  1095.   //Log the information
  1096.   PostLog(nStatusCode, dwBodyLength);
  1097.   //Return the body length
  1098.   return dwBodyLength;
  1099. }
  1100. DWORD CHttpClient::ReturnRedirectMessage(const CString& sURL)
  1101. {
  1102.   //Validate our parameters
  1103.   ASSERT(m_pServer);
  1104.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1105.   ASSERT(pSettings);
  1106.   //Form the body of the response
  1107.   DWORD dwBodyLength = 0;
  1108.   char* pszBody = m_pServer->LoadHTML(302, dwBodyLength);
  1109.   //Form the header of the response
  1110.   CHttpResponseHeader responseHdr;
  1111.   responseHdr.AddStatusCode(302);
  1112.   SYSTEMTIME st;
  1113.   GetSystemTime(&st);
  1114.   responseHdr.AddDate(st);
  1115.   responseHdr.AddServer(pSettings->m_sServerName);
  1116.   responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
  1117.   responseHdr.AddLocation(sURL);
  1118.   if (m_bResponseKeepAlive)
  1119.     responseHdr.AddKeepAlive();
  1120.   responseHdr.AddContentLength(dwBodyLength);
  1121.   responseHdr.AddContentType(_T("text/html"));
  1122.   //Send the header and body all in one
  1123.   TransmitBuffer(m_Socket, responseHdr, (BYTE*)pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
  1124.   //Log the information
  1125.   PostLog(302, dwBodyLength);
  1126.   return dwBodyLength;
  1127. }
  1128. DWORD CHttpClient::ReturnUnauthorizedMessage(const CString& sRealm)
  1129. {
  1130.   //Validate our parameters
  1131.   ASSERT(m_pServer);
  1132.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1133.   ASSERT(pSettings);
  1134.   ASSERT(pSettings->m_bAllowBasicAuthentication || pSettings->m_bAllowNTLMAuthentication);
  1135.   //Form the body of the response
  1136.   DWORD dwBodyLength = 0;
  1137.   char* pszBody = m_pServer->LoadHTML(401, dwBodyLength);
  1138.   //Form the header of the response
  1139.   CHttpResponseHeader responseHdr;
  1140.   responseHdr.AddStatusCode(401);
  1141.   SYSTEMTIME st;
  1142.   GetSystemTime(&st);
  1143.   responseHdr.AddDate(st);
  1144.   responseHdr.AddServer(pSettings->m_sServerName);
  1145.   responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
  1146.   if (pSettings->m_bAllowNTLMAuthentication)
  1147.     responseHdr.AddWWWAuthenticateNTLM(m_Request.m_sAuthenticationResponse);
  1148.   if (pSettings->m_bAllowBasicAuthentication)
  1149.     responseHdr.AddWWWAuthenticateBasic(sRealm);
  1150.   if (m_bResponseKeepAlive)
  1151.     responseHdr.AddKeepAlive();
  1152.   responseHdr.AddContentLength(dwBodyLength);
  1153.   responseHdr.AddContentType(_T("text/html"));
  1154.   //Send the header and body all in one
  1155.   TransmitBuffer(m_Socket, responseHdr, (BYTE*)pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
  1156.   //Log the information
  1157.   PostLog(401, dwBodyLength);
  1158.   return dwBodyLength;
  1159. }
  1160. DWORD CHttpClient::ReturnFileDeletedOkMessage(const CString& /*sFile*/)
  1161. {
  1162.   //Validate our parameters
  1163.   ASSERT(m_pServer);
  1164.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1165.   ASSERT(pSettings);
  1166.   //Form the body of the response
  1167.   DWORD dwBodyLength = 0;
  1168.   char* pszBody = m_pServer->GetFileDeletedHTML(dwBodyLength);
  1169.   //Form the header of the response
  1170.   CHttpResponseHeader responseHdr;
  1171.   responseHdr.AddStatusCode(200);
  1172.   SYSTEMTIME st;
  1173.   GetSystemTime(&st);
  1174.   responseHdr.AddDate(st);
  1175.   responseHdr.AddServer(pSettings->m_sServerName);
  1176.   responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
  1177.   if (m_bResponseKeepAlive)
  1178.     responseHdr.AddKeepAlive();
  1179.   responseHdr.AddContentLength(dwBodyLength);
  1180.   responseHdr.AddContentType(_T("text/html"));
  1181.   //Send the header and body all in one
  1182.   TransmitBuffer(m_Socket, responseHdr, (BYTE*)pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
  1183.   //Log the information
  1184.   PostLog(200, dwBodyLength);
  1185.   //Don't forget to free up the memory
  1186.   delete [] pszBody;
  1187.   return dwBodyLength;
  1188. }
  1189. void CHttpClient::TransmitBuffer(BYTE* byData, DWORD dwSize, CHttpDirectory* /*pDirectory*/, BOOL bForceExpire)
  1190. {
  1191.   //validate our settings
  1192.   ASSERT(m_pServer);
  1193.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1194.   ASSERT(pSettings);
  1195.   ASSERT(pSettings->m_pMimeManager);
  1196.   CHttpResponseHeader responseHdr;
  1197.   //Get the current system time in UTC
  1198.   SYSTEMTIME stCurTime;
  1199.   ::GetSystemTime(&stCurTime);
  1200.   if (m_Request.m_dwHttpVersion > MAKELONG(9, 0)) //No header sent for Http 0.9
  1201.   {
  1202.     //Get the mime type for extension we are about to return
  1203.     CString sMime = pSettings->m_pMimeManager->GetMimeType(m_Request);
  1204.     //Form the header of the response
  1205.     responseHdr.AddStatusCode(200);
  1206.     responseHdr.AddDate(stCurTime);
  1207.     responseHdr.AddServer(pSettings->m_sServerName);
  1208.     responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
  1209.   if (bForceExpire)
  1210.   responseHdr.AddExpires(stCurTime);
  1211.     if (m_bResponseKeepAlive)
  1212.       responseHdr.AddKeepAlive();
  1213.     responseHdr.AddContentLength(dwSize);
  1214.     responseHdr.AddContentType(sMime);
  1215.     //Send the header and body all in one
  1216.     TransmitBuffer(m_Socket, responseHdr, byData, dwSize, pSettings->m_dwWritableTimeout);
  1217.   }
  1218.   else
  1219.   {
  1220.     //Send back the file contents (if not a HEAD request)
  1221.     if (m_Request.m_Verb != CHttpRequest::HTTP_VERB_HEAD)
  1222.     {
  1223.       try
  1224.       {
  1225.         m_Socket.SendWithRetry(byData, dwSize, pSettings->m_dwWritableTimeout);
  1226.       }
  1227.       catch(CWSocketException* pEx)
  1228.       {
  1229.         //Report the error
  1230.         CString sError;
  1231.         sError.Format(_T("CHttpClient::TransmitBuffer, Failed to send to socket, Error:%d"), pEx->m_nError);
  1232.         m_pServer->OnError(sError);
  1233.         pEx->Delete();  
  1234.       }
  1235.     }
  1236.   }
  1237.   //Log the information
  1238.   PostLog(200, dwSize);
  1239. }
  1240.  
  1241. CHttpDirectory* CHttpClient::GetVirtualDirectory(const CString& sDirectory)
  1242. {
  1243.   //Validate our parameters
  1244.   ASSERT(m_pServer);
  1245.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1246.   ASSERT(pSettings);
  1247.   CHttpDirectory* pDirectory = NULL;
  1248.   for (int i=0; i<pSettings->m_Directories.GetSize() && pDirectory == NULL; i++)  
  1249.   {
  1250.     CHttpDirectory* pDir = pSettings->m_Directories.GetAt(i);
  1251.     if (sDirectory.CompareNoCase(pDir->GetAlias()) == 0)
  1252.       pDirectory = pDir;
  1253.   }
  1254.   return pDirectory;  
  1255. }
  1256. int CHttpClient::HexToInt(TCHAR ch)
  1257. {
  1258.   //character is in range of 0-9 subtract ascii value of '0' to get integer
  1259.   if ((ch >= _T('0')) && (ch <= _T('9')))
  1260.     return ch - _T('0');
  1261.   //character is in range of a-z or A-Z subtract ascii value of 'a' and add 10 to get it converted into int
  1262.   if ((ch >= _T('a')) && (ch <= _T('f')))
  1263.     return ch - _T('a') + 10;
  1264.   else if ((ch >= _T('A')) && (ch <= _T('F')))
  1265.     return ch - _T('A') + 10;
  1266.   //Character is not a Hex Digit
  1267.   return -1;
  1268. }
  1269. TCHAR CHttpClient::IntToHex(int Character)
  1270. {
  1271.   //This function only expects nibbles
  1272.   ASSERT(Character >= 0 && Character <= 15);
  1273.   
  1274.   if (Character <= 9)
  1275.     return (TCHAR)(Character + _T('0'));
  1276.   else
  1277.     return (TCHAR)(Character - 10 + _T('A'));
  1278. }
  1279. CString CHttpClient::UTF8ToCString(const CString& sURL)
  1280. {
  1281.   //Get the length of the string to convert from UTF
  1282.   int nInputLen = sURL.GetLength();
  1283.   //Allocate memory to hold the Unicode string
  1284.   LPWSTR lpwszURL = new WCHAR[nInputLen * 4];
  1285.   //Convert the UTF input string to Unicode
  1286.   int nInputIndex = 0;
  1287.   int nOutputIndex = 0;
  1288.   while (nInputIndex < nInputLen)
  1289.   {
  1290.     BYTE cInputChar1 = (BYTE) sURL.GetAt(nInputIndex);
  1291.     if (cInputChar1 <= 0x7f)
  1292.     {
  1293.       //Form the current output character
  1294.       lpwszURL[nOutputIndex] = cInputChar1;
  1295.       //Move onto the next input character
  1296.       nInputIndex++;
  1297.     }
  1298.     else if (nInputIndex < nInputLen-1 && cInputChar1 <= 0xdf)
  1299.     {
  1300.       //Form the current output character
  1301.       lpwszURL[nOutputIndex] = (wchar_t) (((cInputChar1 & 0x1f) << 6) + 
  1302.                                           (sURL.GetAt(nInputIndex+1) & 0x3f));
  1303.       //Move onto the next input character
  1304.       nInputIndex += 2;
  1305.     }
  1306.     else if (nInputIndex < nInputLen-2)
  1307.     {
  1308.       //Form the current output character
  1309.       lpwszURL[nOutputIndex] = (wchar_t) (((cInputChar1 & 0x0f) << 12) + 
  1310.                                           ((sURL.GetAt(nInputIndex+1) & 0x3f) << 6) +
  1311.                                           (sURL.GetAt(nInputIndex+2) & 0x3f));
  1312.       //Move onto the next input character
  1313.       nInputIndex += 3;
  1314.     }
  1315.     else
  1316.     {
  1317.       //skip illegal sequence
  1318.       nInputIndex++;
  1319.     }
  1320.     //Move onto the next output character
  1321.     nOutputIndex++;
  1322.   }
  1323.   //Don't forget to NULL terminate
  1324.   lpwszURL[nOutputIndex] = _T('');
  1325.   //Form a CString version of the Unicode string
  1326.   CString sDecodedURL(lpwszURL);
  1327.   //Tidy up the heap memory we have been using
  1328.   delete [] lpwszURL;
  1329.   //Return the string
  1330.   return sDecodedURL;
  1331. }
  1332. CString CHttpClient::URLEncode(const CString& sURL)
  1333. {
  1334.   CString sEncodedURL;
  1335.   int nLength = sURL.GetLength();
  1336.   LPTSTR pszEncodedURL = sEncodedURL.GetBufferSetLength((nLength*3) + 1);
  1337.   int nOutputIndex = 0;
  1338.   for (int i=0; i<nLength; i++)
  1339.   {
  1340.     //Pull out the current character to evaluate
  1341.     BYTE CurrentChar = (BYTE) sURL.GetAt(i);
  1342.     //Should we encode the character or not? See RFC 1738 for the details.
  1343.     if ((CurrentChar >= '0' && CurrentChar <= '9') ||
  1344.         (CurrentChar >= 'a' && CurrentChar <= 'z') ||
  1345.         (CurrentChar >= 'A' && CurrentChar <= 'Z') ||
  1346.         (CurrentChar == '$') ||
  1347.         (CurrentChar == '-') ||
  1348.         (CurrentChar == '_') ||
  1349.         (CurrentChar == '.') ||
  1350.         (CurrentChar == '+') ||
  1351.         (CurrentChar == '!') ||
  1352.         (CurrentChar == '*') ||
  1353.         (CurrentChar == ''') ||
  1354.         (CurrentChar == '(') ||
  1355.         (CurrentChar == ')') ||
  1356.         (CurrentChar == ','))
  1357.     {
  1358.       pszEncodedURL[nOutputIndex] = CurrentChar;
  1359.       ++nOutputIndex;
  1360.     }
  1361.     else 
  1362.     {
  1363.       pszEncodedURL[nOutputIndex] = _T('%');
  1364.       ++nOutputIndex;
  1365.       TCHAR nNibble = IntToHex((CurrentChar & 0xF0) >> 4);
  1366.       pszEncodedURL[nOutputIndex] = nNibble;
  1367.       ++nOutputIndex;
  1368.       nNibble = IntToHex(CurrentChar & 0x0F);  
  1369.       pszEncodedURL[nOutputIndex] = nNibble;
  1370.       ++nOutputIndex;
  1371.     }
  1372.   }
  1373.   //Don't forget to NULL terminate
  1374.   pszEncodedURL[nOutputIndex] = _T('');
  1375.   sEncodedURL.ReleaseBuffer();
  1376.   return sEncodedURL;
  1377. }
  1378. CString CHttpClient::URLDecode(const CString& sURL)
  1379. {
  1380.   CString sDecodedURL;
  1381.   int nLength = sURL.GetLength();
  1382.   LPTSTR pszDecodedURL = sDecodedURL.GetBufferSetLength(nLength + 1);
  1383.   int nOutputIndex = 0;
  1384.   for (int i=0; i<nLength; i++)
  1385.   {
  1386.     TCHAR c1 = sURL[i];
  1387.     if (c1 != _T('%'))
  1388.     {
  1389.       if (c1 == '+')
  1390.         pszDecodedURL[nOutputIndex] = ' ';  
  1391.       else
  1392.         pszDecodedURL[nOutputIndex] = c1;
  1393.       nOutputIndex++;
  1394.     }
  1395.     else
  1396.     {
  1397.       if (i < nLength-2)
  1398.       {
  1399.         int msb = HexToInt(sURL[i+1]);
  1400.         int lsb = HexToInt(sURL[i+2]);
  1401.         if (msb != -1 && lsb != -1)
  1402.         {
  1403.           int nChar = (msb << 4) + lsb;
  1404.           pszDecodedURL[nOutputIndex] = TCHAR(nChar);
  1405.           nOutputIndex++;
  1406.           i += 2;
  1407.         }
  1408.         else
  1409.         {
  1410.           pszDecodedURL[nOutputIndex] = c1;
  1411.           nOutputIndex++;
  1412.         }
  1413.       }
  1414.       else
  1415.       {
  1416.         pszDecodedURL[nOutputIndex] = c1;
  1417.         nOutputIndex++;
  1418.       }
  1419.     }
  1420.   }
  1421.   //Don't forget to NULL terminate
  1422.   pszDecodedURL[nOutputIndex] = _T('');
  1423.   sDecodedURL.ReleaseBuffer();
  1424.   return sDecodedURL;
  1425. }
  1426. BOOL CHttpClient::MapURLToLocalFilename(CString& sURL, CString& sLocalFile, CString& sPathInfo, BOOL& bDirectory, CHttpDirectory*& pDirectory, DWORD& dwMatchingURL, DWORD& dwMatchingPath)
  1427. {
  1428.   //Setup the default return value from this function
  1429.   BOOL bSuccess = FALSE;
  1430.   sLocalFile.Empty();
  1431.   sPathInfo.Empty();
  1432.   bDirectory = FALSE;
  1433.   pDirectory = NULL;
  1434.   dwMatchingURL = 0;
  1435.   dwMatchingPath = 0;
  1436.   //Convert from Unix to Windows format
  1437.   CString sClientURL(sURL);
  1438.   sClientURL.Replace(_T("/"), _T("\"));
  1439.   //As a security precaution do not allow any URL's which contains any relative parts in it 
  1440.   //(as an example trying to request a file outside of the directories we are serving)
  1441.   //We also exclude URL's with a ":" in them as this is how NTFS streams are accessed
  1442.   if (sClientURL.Find(_T("..")) == -1 && sClientURL.Find(_T(":")) == -1)
  1443.   {
  1444.     pDirectory = NULL;
  1445.     TCHAR sDrive[_MAX_DRIVE];
  1446.     TCHAR sDir[_MAX_DIR];
  1447.     TCHAR sFname[_MAX_FNAME];
  1448.     TCHAR sExt[_MAX_EXT];
  1449.     CString sVirtualDir(sClientURL);
  1450.     sVirtualDir += _T("\"); //Initially try a default directory
  1451.     do
  1452.     {
  1453.       _tsplitpath(sVirtualDir, sDrive, sDir, sFname, sExt);
  1454.       if (_tcslen(sDir))
  1455.       {
  1456.         pDirectory = GetVirtualDirectory(sDir);
  1457.         if (pDirectory == NULL)
  1458.         {
  1459.           sVirtualDir = sDir;
  1460.           sVirtualDir = sVirtualDir.Left(sVirtualDir.GetLength()-1);
  1461.         }
  1462.       }
  1463.     }
  1464.     while (pDirectory == NULL && _tcslen(sDir));
  1465.     if (pDirectory)
  1466.     {
  1467.   CString strPath = pDirectory->GetDirectory();
  1468.       ASSERT(pDirectory->GetDirectory().GetLength());
  1469.       ASSERT(pDirectory->GetAlias().GetLength());
  1470.       //Ignore the alias part of the URL now that we have got the virtual directory
  1471.       CString sAlias = pDirectory->GetAlias();
  1472.       CString sRelativeFile(sClientURL);
  1473.       sRelativeFile = sRelativeFile.Right(sRelativeFile.GetLength() - sAlias.GetLength());
  1474.       //Form the local filename from the requested URL
  1475.       CString sDirectory = pDirectory->GetDirectory();
  1476.       int nLength = sDirectory.GetLength();
  1477.       if (sDirectory.GetAt(nLength-1) != _T('\'))
  1478.         sDirectory += _T("\");
  1479.       sLocalFile = sDirectory; 
  1480.       //Asking for the default filename
  1481.       if (sRelativeFile.IsEmpty())
  1482.       {
  1483.         bDirectory = pDirectory->GetDirectoryListing();
  1484.         if (!bDirectory)
  1485.           sLocalFile += pDirectory->GetDefaultFile(); 
  1486.         dwMatchingURL = sURL.GetLength();
  1487.         dwMatchingPath = sLocalFile.GetLength();
  1488.       }
  1489.       else
  1490.       {
  1491.         //Ensure that we don't have two "" separating the filename from the directory
  1492.         if (sClientURL.Find(_T('\')) == 0)
  1493.           sLocalFile += sRelativeFile.Right(sRelativeFile.GetLength());
  1494.         else
  1495.           sLocalFile += sRelativeFile; 
  1496.         dwMatchingURL = sURL.GetLength();
  1497.         dwMatchingPath = sLocalFile.GetLength();
  1498.         //Keep parsing left to right until we find a piece of the path which is a file.
  1499.         //This is used to work out the PathInfo value
  1500.         CString sTemp(sRelativeFile);
  1501.         int nLocalFileData = 0;
  1502.         BOOL bContinueParse = TRUE;
  1503.         while (bContinueParse)
  1504.         {
  1505.           int nSlash = sTemp.Find(_T('\'));
  1506.           if (nSlash != -1)
  1507.           {
  1508.             nLocalFileData += nSlash;
  1509.             CString sFile(sDirectory + sRelativeFile.Left(nLocalFileData));
  1510.             sTemp = sTemp.Right(sTemp.GetLength() - nSlash - 1);
  1511.             DWORD dwAttributes = GetFileAttributes(sFile);
  1512.             if (dwAttributes == INVALID_FILE_ATTRIBUTES)
  1513.             {
  1514.               bContinueParse = FALSE;
  1515.               sPathInfo = sLocalFile.Right(sLocalFile.GetLength() - sFile.GetLength() + nSlash);
  1516.               sPathInfo.Replace(_T("\"), _T("/"));
  1517.               sLocalFile = sFile.Left(sFile.GetLength() - nSlash - 1);
  1518.               //Remove the PathInfo from the incoming parameter
  1519.               sURL = sURL.Left(sURL.GetLength() - sPathInfo.GetLength());
  1520.               dwMatchingURL = sClientURL.GetLength() - sPathInfo.GetLength();
  1521.               dwMatchingPath = sLocalFile.GetLength();
  1522.             }
  1523.             else if ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  1524.             {
  1525.               bContinueParse = FALSE;
  1526.               sPathInfo = sLocalFile.Right(sLocalFile.GetLength() - sFile.GetLength() - 1);
  1527.               sPathInfo.Replace(_T("\"), _T("/"));
  1528.               sLocalFile = sFile;
  1529.               //Remove the PathInfo from the incoming parameter
  1530.               sURL = sURL.Left(sURL.GetLength() - sPathInfo.GetLength() - 1);
  1531.               dwMatchingURL = sClientURL.GetLength() - sPathInfo.GetLength();
  1532.               dwMatchingPath = sLocalFile.GetLength();
  1533.             }
  1534.             nLocalFileData++; //Move over the directory separator
  1535.           }
  1536.           else
  1537.           {
  1538.             bContinueParse = FALSE;
  1539.             CString sFile(sDirectory + sRelativeFile.Left(nLocalFileData) + sTemp);
  1540.             DWORD dwAttributes = GetFileAttributes(sFile);
  1541.             if (dwAttributes == INVALID_FILE_ATTRIBUTES)
  1542.             {
  1543.               sPathInfo = sTemp;
  1544.               sPathInfo.Replace(_T("\"), _T("/"));
  1545.               sLocalFile = sDirectory + sRelativeFile.Left(nLocalFileData);
  1546.               //Remove the PathInfo from the incoming parameter
  1547.               sURL = sURL.Left(sURL.GetLength() - sPathInfo.GetLength());
  1548.               dwMatchingURL = sClientURL.GetLength() - sPathInfo.GetLength();
  1549.               dwMatchingPath = sLocalFile.GetLength();
  1550.             }
  1551.           }
  1552.         }
  1553.         bDirectory = pDirectory->GetDirectoryListing() && (((GetFileAttributes(sLocalFile) & FILE_ATTRIBUTE_DIRECTORY) != 0));
  1554.         if (bDirectory)
  1555.         {
  1556.           int nURLLength = sURL.GetLength();
  1557.           if (nURLLength && sURL.GetAt(nURLLength-1) != _T('/'))
  1558.             sURL += _T("/");
  1559.         }
  1560.       }
  1561.       bSuccess = TRUE;
  1562.     }
  1563.   }
  1564.   return bSuccess;
  1565. }
  1566. #ifdef _DEBUG
  1567. void CHttpClient::PostLog(int nHTTPStatusCode, DWORD dwBodyLength)
  1568. #else
  1569. void CHttpClient::PostLog(int /*nHTTPStatusCode*/, DWORD /*dwBodyLength*/)
  1570. #endif
  1571. {
  1572. #ifdef _DEBUG
  1573.   //The default is to just TRACE the details
  1574.   //Get the current date and time
  1575.   time_t now = time(NULL);
  1576.   tm* pNow = localtime(&now);
  1577.   //Get the time zone information
  1578.   TIME_ZONE_INFORMATION tzi;
  1579.   GetTimeZoneInformation(&tzi);
  1580.   //Format the date and time appropiately
  1581.   TCHAR sDateTime[64];
  1582.   _tcsftime(sDateTime, 64, _T("[%d/%b/%Y:%H:%M:%S"), pNow);
  1583.   //Display the connections to the console window
  1584.   CString sUser(m_Request.m_sUsername);
  1585.   if (sUser.IsEmpty())
  1586.     sUser = _T("-");
  1587.   TRACE(_T("%d.%d.%d.%d - %s %s %04d] "%s" %d %dn"), 
  1588.         m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b1,
  1589.         m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b2, 
  1590.         m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b3, 
  1591.         m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b4, 
  1592.         sUser, sDateTime, tzi.Bias, m_Request.m_sRequest, nHTTPStatusCode, dwBodyLength);
  1593. #endif        
  1594. }
  1595. BOOL CHttpClient::TransmitFile(CHttpSocket& socket, CHttpResponseHeader& responseHdr, HANDLE hFile, DWORD dwSize, DWORD dwTimeout)
  1596. {
  1597.   //Validate our parameters
  1598.   ASSERT(m_pServer);
  1599.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1600.   ASSERT(pSettings);
  1601.   //Assume the worst
  1602.   BOOL bSuccess = FALSE;
  1603. #ifdef W3MFC_SSL_SUPPORT
  1604.   BOOL bTryUsingSendExtension = (pSettings->m_SSLProtocol == CHttpServerSettings::SSL_NONE);
  1605. #else
  1606.   BOOL bTryUsingSendExtension = TRUE;
  1607. #endif
  1608.   if (bTryUsingSendExtension && _W3MFCData.m_lpfnTransmitFile)
  1609.   {
  1610.     bSuccess = _W3MFCData.TransmitFile(socket, responseHdr, hFile, dwSize);
  1611.     //Handle the error
  1612.     if (!bSuccess)
  1613.     {
  1614.       //Report the error
  1615.       CString sError;
  1616.       sError.Format(_T("CHttpClient::TransmitFile, Failed to send response via TransmitFile, Error:%d"), ::GetLastError());
  1617.       m_pServer->OnError(sError);
  1618.     }
  1619.   }
  1620.   else
  1621.   {
  1622.     //Send the header
  1623. #ifdef W3MFC_SSL_SUPPORT
  1624.     bSuccess = responseHdr.Send(m_Socket, dwTimeout, m_SSL);
  1625. #else
  1626.     bSuccess = responseHdr.Send(socket, dwTimeout);
  1627. #endif
  1628.     if (!bSuccess)
  1629.     {
  1630.       //Report the error
  1631.       CString sError;
  1632.       sError.Format(_T("CHttpClient::TransmitFile, Failed to send to response header, Error:%d"), ::GetLastError());
  1633.       m_pServer->OnError(sError);
  1634.     }
  1635.     //Send the body
  1636.     if (bSuccess)
  1637.     {
  1638.       try
  1639.       {
  1640.         char sBuf[4096];
  1641.         DWORD dwBytesRead = 0;
  1642.         do 
  1643.         {
  1644.           if (::ReadFile(hFile, sBuf, 4096, &dwBytesRead, NULL) && dwBytesRead)
  1645. #ifdef W3MFC_SSL_SUPPORT
  1646.             socket.SendWithRetry(sBuf, dwBytesRead, dwTimeout, m_SSL);
  1647. #else
  1648.             socket.SendWithRetry(sBuf, dwBytesRead, dwTimeout);
  1649. #endif
  1650.         } 
  1651.         while (dwBytesRead);
  1652.         bSuccess = TRUE;
  1653.       }
  1654.       catch(CWSocketException* pEx)
  1655.       {
  1656.         //Report the error
  1657.         CString sError;
  1658.         sError.Format(_T("CHttpClient::TransmitFile, Failed to send response file data, Error:%d"), pEx->m_nError);
  1659.         m_pServer->OnError(sError);
  1660.         pEx->Delete();  
  1661.       }
  1662.     }
  1663.   }
  1664.   return bSuccess;
  1665. }
  1666. BOOL CHttpClient::TransmitBuffer(CHttpSocket& socket, CHttpResponseHeader& responseHdr, BYTE* byData, DWORD dwSize, DWORD dwTimeout)
  1667. {
  1668.   //Validate our parameters
  1669.   ASSERT(m_pServer);
  1670.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1671.   ASSERT(pSettings);
  1672.   //Assume the worst
  1673.   BOOL bSuccess = FALSE;
  1674. #ifdef W3MFC_SSL_SUPPORT
  1675.   BOOL bTryUsingSendExtension = (pSettings->m_SSLProtocol == CHttpServerSettings::SSL_NONE);
  1676. #else
  1677.   BOOL bTryUsingSendExtension = TRUE;
  1678. #endif
  1679.   if (bTryUsingSendExtension && _W3MFCData.m_lpfnTransmitPackets)
  1680.   {
  1681.     bSuccess = _W3MFCData.TransmitBuffer(socket, responseHdr, byData, dwSize);
  1682.     if (!bSuccess)
  1683.     {
  1684.       //Report the error
  1685.       CString sError;
  1686.       sError.Format(_T("CHttpClient::TransmitBuffer, Failed to send response via TransmitPackets, Error:%d"), ::GetLastError());
  1687.       m_pServer->OnError(sError);
  1688.     }
  1689.   }
  1690.   else
  1691.   {
  1692.     //Send the header
  1693. #ifdef W3MFC_SSL_SUPPORT
  1694.     bSuccess = responseHdr.Send(socket, dwTimeout, m_SSL);
  1695. #else
  1696.     bSuccess = responseHdr.Send(socket, dwTimeout);
  1697. #endif
  1698.     if (!bSuccess)
  1699.     {
  1700.       //Report the error
  1701.       CString sError;
  1702.       sError.Format(_T("CHttpClient::TransmitBuffer, Failed to send to response header, Error:%d"), ::GetLastError());
  1703.       m_pServer->OnError(sError);
  1704.     }
  1705.     //Send the body
  1706.     if (bSuccess && dwSize)
  1707.     {
  1708.       try
  1709.       {
  1710. #ifdef W3MFC_SSL_SUPPORT
  1711.         socket.SendWithRetry(byData, dwSize, dwTimeout, m_SSL);
  1712. #else
  1713.         socket.SendWithRetry(byData, dwSize, dwTimeout);
  1714. #endif
  1715.         bSuccess = TRUE;
  1716.       }
  1717.       catch(CWSocketException* pEx)
  1718.       {
  1719.         //Report the error
  1720.         CString sError;
  1721.         sError.Format(_T("CHttpClient::TransmitBuffer, Failed to send to response body, Error:%d"), pEx->m_nError);
  1722.         m_pServer->OnError(sError);
  1723.         pEx->Delete();  
  1724.       }
  1725.     }
  1726.   }
  1727.   return bSuccess;
  1728. }
  1729. void CHttpClient::SetRequestToStop()
  1730. {
  1731.   //Let the base class do its thing
  1732.   CThreadPoolClient::SetRequestToStop();
  1733.   //Set the event which signals that we want this worker thread to exit
  1734.   m_StopEvent.SetEvent();
  1735. }
  1736. BOOL CHttpClient::GetKeySizeServerVariable(int& nKeySize)
  1737. {
  1738.   //Validate our parameters
  1739.   ASSERT(m_pServer);
  1740.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1741.   ASSERT(pSettings);
  1742.   //What will be the return value
  1743.   BOOL bSuccess = FALSE;
  1744.   nKeySize = 0;
  1745. #ifdef W3MFC_SSL_SUPPORT
  1746.   if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  1747.   {
  1748.     SSL_get_cipher_bits(m_SSL, &nKeySize);
  1749.     bSuccess = TRUE;
  1750.   }
  1751. #endif
  1752.   return bSuccess;
  1753. }
  1754. BOOL CHttpClient::GetServerKeySizeServerVariable(int& nKeySize)
  1755. {
  1756.   //Validate our parameters
  1757.   ASSERT(m_pServer);
  1758.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1759.   ASSERT(pSettings);
  1760.   //What will be the return value
  1761.   BOOL bSuccess = FALSE;
  1762.   nKeySize = 0;
  1763. #ifdef W3MFC_SSL_SUPPORT
  1764.   if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  1765.   {
  1766.     EVP_PKEY* pKey = SSL_get_privatekey(m_SSL);
  1767.     if (pKey)
  1768.     {
  1769.       nKeySize = EVP_PKEY_bits(pKey);
  1770.       bSuccess = TRUE;
  1771.     }
  1772.   }
  1773. #endif
  1774.   return bSuccess;
  1775. }
  1776. BOOL CHttpClient::GetCertSerialNumberServerVariable(long& nSerialNumber)
  1777. {
  1778.   //Validate our parameters
  1779.   ASSERT(m_pServer);
  1780.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1781.   ASSERT(pSettings);
  1782.   //What will be the return value
  1783.   BOOL bSuccess = FALSE;
  1784.   nSerialNumber = 0;
  1785. #ifdef W3MFC_SSL_SUPPORT
  1786.   if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  1787.   {
  1788.     X509* pCert = SSL_get_certificate(m_SSL);
  1789.     if (pCert)
  1790.     {
  1791.       ASN1_INTEGER* pSerialNumber = X509_get_serialNumber(pCert);
  1792.       if (pSerialNumber)
  1793.       {
  1794.         nSerialNumber = ASN1_INTEGER_get(pSerialNumber);
  1795.         bSuccess = TRUE;
  1796.       }
  1797.     }
  1798.   }
  1799. #endif
  1800.   return bSuccess;
  1801. }
  1802. BOOL CHttpClient::GetCertIssuerServerVariable(char*& szIssuer)
  1803. {
  1804.   //Validate our parameters
  1805.   ASSERT(m_pServer);
  1806.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1807.   ASSERT(pSettings);
  1808.   //What will be the return value
  1809.   BOOL bSuccess = FALSE;
  1810.   szIssuer = NULL;
  1811. #ifdef W3MFC_SSL_SUPPORT
  1812.   if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  1813.   {
  1814.     X509* pCert = SSL_get_certificate(m_SSL);
  1815.     if (pCert)
  1816.     {
  1817.       szIssuer = X509_NAME_oneline(X509_get_issuer_name(pCert), NULL, NULL);
  1818.       bSuccess = TRUE;
  1819.     }
  1820.   }
  1821. #endif
  1822.   return bSuccess;  
  1823. }
  1824. BOOL CHttpClient::GetCertSubjectServerVariable(char*& szSubject)
  1825. {
  1826.   //Validate our parameters
  1827.   ASSERT(m_pServer);
  1828.   CHttpServerSettings* pSettings = m_pServer->GetSettings();
  1829.   ASSERT(pSettings);
  1830.   //What will be the return value
  1831.   BOOL bSuccess = FALSE;
  1832.   szSubject = NULL;
  1833. #ifdef W3MFC_SSL_SUPPORT
  1834.   if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  1835.   {
  1836.     X509* pCert = SSL_get_certificate(m_SSL);
  1837.     if (pCert)
  1838.     {
  1839.       szSubject = X509_NAME_oneline(X509_get_subject_name(pCert), NULL, NULL);
  1840.       bSuccess = TRUE;
  1841.     }
  1842.   }
  1843. #endif
  1844.   return bSuccess;
  1845. }
  1846. #ifndef W3MFC_NO_ISAPI_SUPPORT
  1847. BOOL CHttpClient::TransmitFile(CHttpSocket& socket, CHttpResponseHeader& responseHdr, HSE_TF_INFO* pInfo)
  1848. {
  1849.   return _W3MFCData.TransmitFile(socket, responseHdr, pInfo);
  1850. }
  1851. #endif
  1852. BOOL CHttpClient::PreHandleGetPostHead()
  1853. {
  1854.   //This allows derived classes to internally handle GET, POST or HEAD requests.
  1855.   //Return TRUE in your derived classes to tell the framework that the request
  1856.   //has been handled and stops the framework from implementing its default processing
  1857.   //for a URL
  1858.   //In this base class we of course allow default processing to occur
  1859.   return FALSE;
  1860. }