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

CA认证

开发平台:

Visual C++

  1. /*
  2. Module : W3Mfc.cpp
  3. Purpose: Implementation for a simple MFC class encapsulation of a HTTP server
  4. Created: PJN / 22-04-1999
  5. History: PJN / 24-06-1999 1.  Implemented support for "HEAD" command
  6.                           2.  Sample provided now also displays the HTTP verb used
  7.                           3.  Sample provided now also displays the date and time of each request
  8.                           4.  Now fully supports multiple virtual directories
  9.                           5.  Now fully supports URL's with encoded characters
  10.                           6.  Implemented support for "DELETE" command
  11.                           7.  Now returns an "Allow:" HTTP header
  12.                           8.  Timeout for requests is now 90 seconds if built for debug
  13.                           9.  Now supports directory listing
  14.                           10. User name is now displayed in the log window
  15.          PJN / 29-02-2000 1.  Fixed a number of VC 6 level 4 warnings
  16.                           2.  Now empties the username and password once they are used
  17.                           3.  Now implements W3C Common Logfile logging to the console window
  18.          PJN / 15-04-2001 1.  Updated copyright information   
  19.                           2.  A new generalised thread pool wrapper class is now included which can
  20.                           be used in other projects.
  21.                           3.  A new generalised sockets wrapper class is now included which can be 
  22.                           used in other winsock projects
  23.          PJN / 23-04-2001 1. Fixed a stack overwrite issue in CHttpResponseHeader::DateToStr
  24.                           2. Fixed a bug in CHttpClient::TransmitFile which was causing "304 Not Modified"
  25.                           headers to never be returned
  26.          PJN / 25-07-2001 1. Code now uses Winsock 2 functionality, namely "WSAEventSelect" to avoid a busy loop
  27.                           in the listening socket thread. This means that you will have to have Winsock 2 
  28.                           downloaded and installed if running on Windows 95 which did not ship with 
  29.                           Winsock 2 built in.
  30.          PJN / 23-08-2001 1. Added support for CGI v1.1 (has been verfied with perl scripts and batch files)
  31.                           2. Added support for reverse DNS lookups
  32.                           3. Now fully supports POST HTTP method.
  33.                           4. Following values have been added to CHttpRequest:
  34.                              m_pszRawRequest, m_pszRawEntity, m_sRemoteHost and m_sContentType
  35.                           5. Improved the robustness of the code by making sure exceptions are caught
  36.          PJN / 30-09-2001 1. Fixed a bug in CWSocket::Receive which can occur when a disconnection occurs
  37.                           while a receive is in progress
  38.                           2. Fixed a bug where entities sent i.e. m_pszRawEntity did not correctly handle the 
  39.                           case where it had enbedded NULL's e.g. a file upload. Thanks to Christian Hett for 
  40.                           spotting this problem.
  41.                           3. Removed some unnecessary memcpy's from CHttpClient::ParseRequest
  42.                           4. Made the main program configurable via an ini file instead of hard coding all the
  43.                           settings.
  44.                           5. Fixed a resource leak on an anonymous pipe handle in CHttpClient::TransmitCGIResponse.
  45.          PJN / 03-11-2001 1. Fixed an issue where socket sends would sometimes throw the exception WSAEWOULDBLOCK.
  46.                           The httpsocket class now includes a "SendWithRetry" method which handles this case.
  47.          PJN / 27-12-2001 1. Fixed an exception memory leak in the method CHttpSocket::SendWithRetry. Thanks 
  48.                           to Olivier Meyer for spotting this problem.
  49.                           2. Removed an unreferrenced variable from CHttpSocket::ReadResponse
  50.                           3. Added a flag to TransmitFile to allow the transmission of an "Expires: " header
  51.                           4. Added CHttpDirectory parameter to all transmit methods. Allows derived classes
  52.                           more control over the response procedure.
  53.                           5. Added optional Non-NT authentication to the web server at the virtual directory
  54.                           level. 
  55.                           6. Reviewed TRACE statements throughtout W3MFC for completeness and validity
  56.                           7. Addition of a CHttpClient::TransmitBuffer method to allow for easy transmission of 
  57.                           in-memory generated responses. Thanks to "Golden Crater" for most of those suggestions.
  58.                           8. W3MFC now takes advantage of the MS Winsock extension API "TransmitFile". This
  59.                           should improve the performance of the code by avoiding inordinate kernel transitions
  60.                           on NT based operating systems.
  61.                           9. Includes a new error reporting mechanism via the CHttpServer::OnError method
  62.                           10. Now includes a nice icon for the generated binary
  63.                           11. Version info resource is now included in the generated binary
  64.                           12. Modified "Return..." functions to return body length sent
  65.                           13. Check all PostLog calls to ensure indicated parameter size is correct
  66.                           14. W3MFC now takes advantage of the MS Winsock extension API "TransmitPackets". This
  67.                           should improve the performance of the code by avoiding inordinate kernel transitions
  68.                           on Windows XP or later. Please note that I have been unable to test this feature so 
  69.                           feeback on this would be appreciated.
  70.          PJN / 08-01-2002 1. Code only uses TransmitFile and TransmitPackets APIs if running on NT/2000/XP/.Net Server
  71.                           2. Provided a virtual CHttpClient::TransmitFile and CHttpClient::TransmitBuffer functions. 
  72.                           The default implemenations just pass the buck to the _W3MFC_DATA function pointers if 
  73.                           available.
  74.                           3. Made CHttpClient::HandleClient function virtual.
  75.                           4. Fixed an issue in CHttpClient::TransmitDirectory where created URL's could sometimes forget 
  76.                           to put in directory separators in the URL.
  77.                           5. Updated copyright messages to be 2002.
  78.                           6. Provided a virtual CHttpClient::ParseRequestLine to allow derived classes to easily pull
  79.                           out any additional http headers e.g. "User-Agent" or "Accept-Language" etc.
  80.                           7. Provided a virtual CHttpClient::FormCGIEnvironment to allow derived classes to easily change
  81.                           the environment variables sent to CGI processes.
  82.                           8. Fixed a serious bug in CHttpResponseHeader::GetData while code was compiled for UNICODE
  83.                           9. Addition of a very handy new "CW32Handle" class which implements a "Smart Pointer" class
  84.                           for Win32 Handles. For one thing it looks after calling CloseHandle in the destructor. The class
  85.                           turns out to be very handy when you are implementing CGI in this web server as you have to
  86.                           create loads of Win32 handles such as anonymous pipes etc.
  87.                           10. Improved the error reporting in CHttpClient::TransmitCGIResponse
  88.                           11. Rewrote the CGI handling code in CHttpClient::TransmitCGIResponse to use the information 
  89.                           provided by MS Knowledge base article "Q190351".
  90.          PJN / 26-01-2002 1. CIOCP9x clas: added an additional semaphore as I have forgotten that we need to synchronise 
  91.                           the removal of items from the queue in addition to synchronising the addition of items to the 
  92.                           queue.
  93.                           2. Fixed a level 4 warning in the CHttpClient class.
  94.                           3. Only now uses TransmitPackets and TransmitFile if running 2000 / XP or .Net Server. Thanks 
  95.                           to Olivier Meyer for spotting this problem on NT 4.
  96.          PJN / 21-02-2002 1. Fixed an issue in CHttpClient::GetCGICommandLine where the code was using RegQueryValue 
  97.                           instead of RegQueryValueEx which is the recommended way of doing registry queries in Win32.
  98.                           Thanks to Josh Clarke for spotting this problem.
  99.                           2. CGI command line is now expanded with any environment variables it may contain. Again 
  100.                           thanks goes to Josh Clarke for this nice update.
  101.          PJN / 23-03-2002 1. W3MFC ships with a sample CGI app "TestCGI.exe"
  102.                           2. CHttpClient::GetCGICommandLine function now defaults to the local file path if a registry 
  103.                           entry cannot be found for it. Thanks to Gilad Novik for this suggestion.
  104.          PJN / 23-05-2002 1. Now fully supports SSL via the OpenSSL open source Library.
  105.                           2. Removed IOCP9x module from project as not required.
  106.                           3. Fixed a bug in CHttpServer::ListenSocketFunction which was causing the thread pool to initialize
  107.                           incorrectly.
  108.          PJN / 24-05-2002 1. Fixed a bug in the SSL code path which was causing a crash in CHttpClient::TransmitBuffer.
  109.                           2. Provision of wrapper classes for OpenSSL C type variables used by W3MFC
  110.                           3. Tidied up the SSL code in CHttpClient::HandleClient
  111.          PJN / 25-05-2002 1. Improved the performance of CHttpClient::URLDecode method
  112.                           2. Improved the performance of CHttpClient::TransmitDirectory. Thanks to "Jim" for this fix.
  113.                           3. URL's transmitedd down to client in CHttpClient::TransmitDirectory are now URL encoded.
  114.                           4. Fixed a crash which was occurring for some requests in CHttpClient::ParseRequest where the code
  115.                           ended up parsing into the entity body instead of stopping when it reached the separator after the
  116.                           http header. Thanks to Harold B Johns for spotting this.
  117.          PJN / 29-05-2002 1. Environment variables for CGI processes now includes all the environment variables which W3MFC
  118.                           itself has. These missing environment variables were causing CGI programs to fail in calls to
  119.                           CoInitialize if they were using COM. Thanks to Harold B Johns for spotting this.
  120.          PJN / 30-05-2002 1. Fixed a #include issue when doing a non SSL build. Thanks to Harold B Johns for spotting this.
  121.                           2. Fixed an issue where a request for a non existent CGI file caused the web server to become
  122.                           unresponsive. Thanks to Harold B Johns for spotting this.
  123.                           3. Fixed an issue in the CGI code when SSL is enabled. Thanks to Gilad Novik for reporting this
  124.                           problem.
  125.          PJN / 14-06-2002 1. Fixed a problem in CHttpClient::FindNextTerminatorFromRequest which was parsing out header
  126.                           details incorrectly. Thanks to Gilad Novik for reporting this problem.                         
  127.          PJN / 28-07-2002 1. Now CHttpMimeManager can be replaced at runtime. This allows the mime map to be easily configured
  128.                           or replaced with a custom implementation.
  129.                           2. Mime map as used by the sample app is now configured from the W3MFC ini file instead of from
  130.                           the system registry. In addition the shipped W3MFC ini file now includes a fully fleshed out mime 
  131.                           section
  132.                           3. You can now improve the robustness of the SSL behaviour by initializing the OpenSSL PRNG (Pseudo
  133.                           Random Number generator) with the contents of a file as specified via 
  134.                           CHttpServerSettings::m_sSSLRandomnessFile.
  135.                           4. A fresh default web site is now shown using the default ini settings, instead of expecting a web 
  136.                           site to be configured at c:inetpubwwwroot
  137.                           5. Improved the performance of looking up mime types by implementing a hash table for storage
  138.          PJN / 18-08-2002 1. Now uses v1.09 of the CThreadPoolServer class.                 
  139.                           2. Sample app now allows you to decide via a ini value whether or not to use the CIOCPThreadPoolQueue
  140.                           class instead of the CDirectedThreadPoolQueue class. While I was at it, I avoiding an issue with
  141.                           leaving an item on the Q if updating the "Get" semaphores failed.
  142.          PJN / 17-10-2002 1. Fixed a bug in CHttpClient::HexToInt which was causing it to not work for upper case characters.
  143.                           Thanks to Frank Schmidt for spotting this problem.
  144.                           Failure to setup thread pool recycling is now reported as an error.
  145.          PJN / 16-11-2002 1. Class now supports the use of the "Connection: Keep-Alive" Header.
  146.                           2. Removed the StringReplace method and replaced it with CString::Replace.
  147.                           3. Fixed some Log message's text to correctly reflect the function they are used in.
  148.                           4. Code now makes the call to CHttpClient::AllowThisConnection before the incoming request is parsed.
  149.                           5. Fixed a typo in the name of the CHttpClient::HandleDirectoryAuthorization function
  150.                           6. Made the operation of the delivery of the "Expires" header contingent on a configurable setting
  151.                           7. CHttpResponseHeader::AddW3MfcAllowFields now returns that it can handle POST requests
  152.                           8. The "DELETE" verb support is now contingent on a configurable setting.
  153.                           9. Fixed a typo in the creation of the "SERVER_PROTOCOL" CGI environment variable
  154.                           10. Updated the sample CGI app to also send a Content-Length HTTP header. This allows the sample
  155.                           app to work correctly when it is used in conjuction with HTTP Keep Alives  
  156.          PJN / 17-11-2002 1. Optimized the use of the Keep Alives variables in the function CHttpClient::HandleClient
  157.                           2. Implemented code to find whether CGI programs send Keep Alives.
  158.          PJN / 18-11-2002 1. Now allows anonymous access to be enabled / disabled
  159.                           2. Now allows Basic authentication to be enabled / disabled.
  160.                           3. Reworked the Base64 class to be based on the ATL Server Base64 routines in ATL Server in VC.Net
  161.                           4. Renamed and Reworked the CHttpClient::ReturnUnauthorizedMessage method.
  162.                           5. Impersonation handle used during Basic authentication now is a CW32Handle instance instead of a 
  163.                           raw SDK handle
  164.                           6. Now fully supports NTLM Authentication via the SSPI interface. The code is enabled for support
  165.                           for Kerberos, "Negotiate" and Digest authentication which will be added in a future release. The use 
  166.                           of SSPI support can be changed via the compile time define "W3MFC_NO_SSPI_SUPPORT". Thanks to 
  167.                           Harold B Johns for suggesting this.
  168.                           7. Fixed a problem in CHttpClient::ParseRequest which was causing failures to parse a certain line
  169.                           to be overwritten upon successfull parsing of subsequent lines. 
  170.                           8. test CGI app now is implemented without MFC support and deliberatly does not use a Content-Length
  171.                           or Keep-Alive header for testing purposes.
  172.                           9. Tidied up the importing of various header files throughout W3MFC and also the associated
  173.                           #pragma messages which these something display.
  174.          PJN / 18-11-2002 1. CHttpSocket::ReadResponse now uses waitable timers (if it can) instead of a loop which has calls
  175.                           to Sleep. This should improve the scalabilty of the code under heavy load. Please note that if you
  176.                           want to compile the code, then you will need to download the CWaitableTimer source code separately
  177.                           from my web site and copy in the wtimer.h & wtimer.cpp into your W3MFC's source code directory.
  178.                           2. Added code to protect against NTFS alternate streams being accessed by client browsers.
  179.                           3. Improved the robustness of parsing the authorization header fields.
  180.          PJN / 20-11-2002 1. Fixed a number of level 4 warnings about unreferrenced variables. Thanks to Harold Johns for 
  181.                           reporting these.
  182.                           2. Updated the documentation to refer to the fact that you will need an up to date Platform SDK 
  183.                           to be installed to compile W3MFC with SSPI support.
  184.                           3. Fixed a memory leak of CHttpRequest objects which can occur when you shutdown the web server and
  185.                           you are using a directed thread pool queue and there are outstanding items in the queue which are
  186.                           not shutdown requests
  187.          PJN / 03-02-2003 1. W3MFC now compares HTTP headers without regard to case. Thanks to Gilad Novik and Frank Hahn for 
  188.                           reporting these problems.
  189.                           2. Tidied up inclusion of afxpriv.h throughout W3MFC modules.
  190.          PJN / 21-02-2003 1. Made the m_Directories member of CHttpServerSettings a pointer array. This allows client code
  191.                           to add their own derived instances of CHttpDirectory to the array. This allows per directory 
  192.                           customisation of the web server. This change also necessitated changing the settings class of the 
  193.                           CHttpServer to be a pointer also. Thanks to "Edgar" for this update.
  194.                           2. Remove the digest authentication boolean from the settings class as Digest authentication is 
  195.                           currently not supported.
  196.                           3. Made the CHttpClient::LoadHTMLResource method virtual
  197.                           4. Moved a lot of the CHttpClient implementation code to CHttpDirectory. This allows more additional
  198.                           complex client customisation of the code.
  199.                           5. Split off the CHttpDirectory class into its own module.
  200.                           6. Implemented a virtual CHttpDirectory::HandleClient. This allows customisation of per directory
  201.                           responses. Thanks to "Edgar" for this suggestion.
  202.          PJN / 22-02-2003 1. Fixed a bug in the parsing of SSL requests which was causing heap corruption problems on
  203.                           subsequent reads of SSL requests on the same thread.
  204.                           2. Reworked the CHttpClient::HandleClient to avoid having to call various functions when the code
  205.                           needs to exit prematurely
  206.                           3. Added a member variable "m_bResponseKeepAlive" to avoid having to pass a keep alive variable
  207.                           throughout all the CHttpClient code.
  208.                           4. Fixed a deadlock bug in CHttpServer::Stop. Thanks to "Edgar" for reporting this problem.
  209.                           5. modified the Mime manager class method "GetMimeType" to be sent the full request rather than just
  210.                           the extension of the URL when it is called to determine the mime type.
  211.                           6. Addition of a string version of the HTTP verb to CHttpRequest. This speeds up the CGI and 
  212.                           ISAPI implementations somewhat.
  213.                           7. Addition of a hash table in the request structure which contains all the HTTP request headers. These
  214.                           values are now available via CGI or ISAPI
  215.                           8. Split of the CGI implementation into its own module and made it optional via a preprocessor directive
  216.                           9. Split of the ISAPI implementation into its own module and made it optional via a preprocessor directive
  217.                           10. W3MFC now uses Win32 TransmitFile API in SSL configuration and only falls back to user mode sockets
  218.                           if SSL is actively being used.
  219.                           11. W3MFC now supports PATH_INFO information in URL's
  220.                           12. Optimized loading of error pages which W3MFC uses
  221.          PJN / 02-03-2002 1. Removed the function CHttpDirectory::SetClient as it can lead to thread synchronisation problems. 
  222.                           Thanks to "Edgar" for reporting this problem.
  223.          PJN / 03-03-2202 1. Added a few defines to allow the W3MFC to compile if you do not have the latest version of the Platform
  224.                           SDK installed. Thanks to "Edgar" for reporting this.
  225.                           2. Fixed a copy and paste gremlin in CHttpServer::Start which was causing a critical section to not be
  226.                           acquired. Thanks to "Edgar" for reporting this.
  227.                           3. Removed the use of "friend classes" entirely throughout the W3MFC codebase. This avoids potential 
  228.                           compilation problems in any derived classes used by client code of W3MFC.
  229.                           4. Addition of a number of preprocessor defines, namely W3MFC_EXT_CLASS, THRDPOOL_EXT_CLASS and 
  230.                           SOCKMFC_EXT_CLASS. This allows the classes to easily be added and exported from a MFC extension dll.
  231.          PJN / 12-09-2003 1. Removed double definition of SCRIPT_NAME from CGI environment. Thanks to Dave Horner for reporting
  232.                           this.
  233.                           2. SCRIPT_NAME CGI environment variable now uses forward slashes rather than back slashes as
  234.                           directory separators. Thanks to Dave Horner for reporting this problem.
  235.                           3. Added a "REQUEST_URI" CGI environment variable. Thanks to Dave Horner for reporting this.
  236.                           4. CGI implementation now returns a HTTP return code line if one if the CGI script does not provide one.
  237.                           Again thanks to Dave Horner for reporting this issue.
  238.                           5. CGI implementation now returns immedately from CHttpCGI::ReadFromClientStdout from a socket error is
  239.                           detected. Again thanks to Dave Horner for reporting this issue.
  240.                           6. "PATH_TRANSLATED" CGI and ISAPI environment variable is now reported as an absolute path. Again thanks 
  241.                           to Dave Horner for reporting this issue.
  242.                           7. "SCRIPT_NAME" CGI and ISAPI environment variable now includes an initial "/". Again thanks to Dave 
  243.                           Horner for reporting this issue.
  244.                           8. CGI now uses pClient->m_Request.m_dwRawEntitySize variable when determining when W3MFC needs to 
  245.                           write to the CGI child process.
  246.                           9. ISAPI implementation now sends just the HTTP body to client ISAPI dlls instead of the whole HTTP
  247.                           request. Thanks to Michael St. Laurent for reporting this problem.
  248.          PJN / 03-11-2003 1. Simplified the code in CHttpSocket::ReadResponse. Thanks to Clarke Brunt for reporting this issue.
  249.          PJN / 10-11-2003 1. URL Encoded spaces as "+" are now correctly handled. Thanks to Dan Baker for reporting this issue. 
  250.                           2. CHttpRequest now includes a m_sRawURL member variable which provides access to the raw URL 
  251.                           before it is URL decoded. Thanks to Dan Baker for suggesting this addition.
  252.                           3. Shipped binary for W3MFC is now linked with the OpenSSL 0.9.6l which is the latest version currently.
  253.          PJN / 30-03-2004 1. Tidied up the interaction of the various classes by removing all friend classes
  254.          PJN / 25-08-2004 1. The binaries included in the download now link against OpenSSL 0.9.7d.
  255.                           2. Per thread cleanup is now done for OpenSSL. Again thanks to Leandro Gustavo Biss Becker for reporting 
  256.                           this problem.
  257.                           3. OpenSSL is now configured by the W3MFC sample app to operate in a thread safe manner. Again thanks 
  258.                           to Leandro Gustavo Biss Becker for reporting this problem.
  259.                           4. Application initialization of OpenSSL has been taken out of W3MFC and is now the responsibility of 
  260.                           your application. See the sample W3MFC application code in main.cpp for an example on how to correctly
  261.                           initialize and terminate OpenSSL.
  262.                           5. CSSL::Close() now calls SSL_shutdown to ensure SSL connections are properly terminated. Thanks to 
  263.                           to Leandro Gustavo Biss Becker for reporting this problem.
  264.                           6. W3MFC now correctly handles UTF8 encoded URL requests. Thanks to Huang Wei for reporting this problem
  265.                           and providing the fix.
  266.          PJN / 15-10-2004 1. Removed an unnecessary ASSERT from CHttpClient::MapURLToLocalFilename. Thanks to Jan Bares for 
  267.                           reporting this problem.
  268.                           2. Changed the behaviour of the code in CHttpClient::MapURLToLocalFilename as follows:
  269.                           Before Change
  270.                           Requesting the URL "/name" would return the file "name" in the root directory of the web server even if
  271.                           a "/name" virtual directory existed. If "name" did not exist in the root directory then a 404 error 
  272.                           would be returned
  273.                           After Change
  274.                           Requesting the URL "/name" will return the virtual directory "/name" if such a virtual directory exists. 
  275.                           If not then the file "name" in the root directory will be returned.
  276.                           Thanks to Jan Bares for pointing out this behaviour which is inconsistent with other Web Server implementations.
  277.                           3. URLs which include "@" now are parsed correctly. Previously the code was parsing the URI
  278.                           expecting it to contain username and password in the URL itself. Instead when the URI arrives at the 
  279.                           server it is not in the URI itself but is represented in the HTTP request headers. Thanks to Jan Bares for 
  280.                           pointing out this problem.
  281.                           4. Passthrough authentication can now be disabled via a new CHttpServerSettings::m_bPerformPassthroughAuthentication
  282.                           setting. This is useful where you want to setup per directory protection using a username / password pair but
  283.                           you do not want to use these credentials in an attempt to impersonate that user by calling the SDK function 
  284.                           "LogonUser". Again thanks to Jan Bares for this suggestion.
  285.          PJN / 11-11-2004 1. Added a m_sRawExtra variable to CHttpRequest. This value is now passed to CGI and ISAPI instead of m_sExtra. 
  286.                           This allows apps to correctly parse form parameters. Thanks to Jan Bares for reporting this problem.
  287.          PJN / 19-02-2004 1. Fixed a bug when directory lists were displayed by W3MFC. It incorrectly always dropped the last entry from
  288.                           the listing. Thanks to Pablo Romero for reporting this bug.
  289. Copyright (c) 1999 - 2005 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)
  290. All rights reserved.
  291. Copyright / Usage Details:
  292. You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
  293. when your product is released in binary form. You are allowed to modify the source code in any way you want 
  294. except you cannot modify the copyright details at the top of each module. If you want to distribute source 
  295. code with your application, then you are only allowed to distribute versions released by the author. This is 
  296. to maintain a single distribution point for the source code. 
  297. */
  298. //////////////// Includes ////////////////////////////////////////////
  299. #include "stdafx.h"
  300. #include "..resource.h"
  301. #include "SocMFC.h"
  302. #include "HttpClient.h"
  303. #include "W3Mfc.h"
  304. #include "Win32Handle.h"
  305. #ifdef W3MFC_SSL_SUPPORT
  306. #include "OpenSSLMfc.h"
  307. #include <opensslrand.h>
  308. #endif
  309. #ifndef __AFXPRIV_H__
  310. #pragma message("To avoid this message please put afxpriv.h in your PCH (normally stdafx.h)")
  311. #include <afxpriv.h>
  312. #endif
  313. //////////////// Macros / Defines /////////////////////////////////////
  314. //automatically pull in Winsock 2
  315. #pragma comment(lib, "Ws2_32.lib")
  316. //automatically pull in SSPI (if required)
  317. #ifndef W3MFC_NO_SSPI_SUPPORT
  318. //#pragma comment(lib, "E:\sdk\Lib\secur32.lib")
  319. #endif
  320. #ifndef SEC_E_OK
  321. #define SEC_E_OK ((SECURITY_STATUS)0x0000)
  322. #endif
  323. #ifdef _DEBUG
  324. #define new DEBUG_NEW
  325. #undef THIS_FILE
  326. static char THIS_FILE[] = __FILE__;
  327. #endif
  328. //////////////// Implementation //////////////////////////////////////
  329. CHttpServerSettings::CHttpServerSettings()
  330. {
  331.   m_nPort = 80;                  //Default to the standard HTTP port
  332.   m_bBind = FALSE;               //Default to not binding to a specific IP address
  333. #ifdef _DEBUG
  334.   m_dwIdleClientTimeout = 90000; //Default to client idle timeout of 90 seconds (when in debug mode)
  335. #else
  336.   m_dwIdleClientTimeout = 30000; //Default to client idle timeout of 30 seconds
  337. #endif
  338.   //Default root directory will be where the exe is running from
  339.   TCHAR sPath[_MAX_PATH];
  340.   GetModuleFileName(NULL, sPath, _MAX_PATH);
  341.   TCHAR sDrive[_MAX_DRIVE];   
  342.   TCHAR sDir[_MAX_DIR];
  343.   _tsplitpath(sPath, sDrive, sDir, NULL, NULL);
  344.   _tmakepath(sPath, sDrive, sDir, NULL, NULL);
  345.   CHttpDirectory* pDir = new CHttpDirectory;
  346.   pDir->SetDirectory(sPath);    
  347.   pDir->SetAlias(_T('/'));
  348.   pDir->SetDefaultFile(_T("default.htm")); //Default filename returned for root requests will be "default.htm"
  349.   m_Directories.Add(pDir);
  350.   m_sServerName = _T("MiniCA Web Server"); //Default server name will be the name of the MFC classes i.e "W3MFC" plus the current version number 
  351.   m_pRuntimeClientClass = RUNTIME_CLASS(CHttpClient); //Default class to use is CHttpClient
  352.   m_nThreadPoolSize = 10;
  353.   m_bDNSLookup = FALSE;
  354.   m_dwWritableTimeout = 10000;
  355.   m_bEnableThreadLifetime = FALSE;
  356.   m_dwThreadLifetime = 120;
  357.   m_pMimeManager = NULL;
  358.   m_bUseIOCPQueue = FALSE;
  359.   m_bKeepAlives = TRUE;
  360.   m_bAutoExpire = FALSE;
  361.   m_bAllowDeleteRequest = FALSE;
  362. #ifndef W3MFC_NO_CGI_SUPPORT
  363.   m_dwCGIResponseBufferSize = 4096;
  364. #endif
  365.   m_bAllowAnonymous = TRUE;
  366.   m_bAllowBasicAuthentication = TRUE;
  367.   m_bAllowNTLMAuthentication = FALSE;
  368.   m_bPerformPassthroughAuthentication = TRUE;
  369. #ifndef W3MFC_NO_ISAPI_SUPPORT
  370.   m_bCacheISAPI = TRUE;
  371.   m_pISAPIManager = NULL;
  372.   m_pISAPI = NULL;
  373. #endif
  374. #ifndef W3MFC_NO_CGI_SUPPORT
  375.   m_pCGI = NULL;
  376. #endif
  377. #ifdef W3MFC_SSL_SUPPORT
  378.   m_SSLProtocol = SSL_NONE;
  379.   m_sServerCertificateFile = _T("W3MFC.pem");
  380.   m_bReuseSessions = TRUE;
  381.   m_dwSSLSessionTimeout = 300;
  382.   m_dwSSLNegotiationTimeout = 10000;
  383. #endif
  384. }
  385. CHttpServerSettings::~CHttpServerSettings()
  386. {
  387.   FreeDirectoryArray();
  388. }
  389. void CHttpServerSettings::FreeDirectoryArray()
  390. {
  391.   for (int i=0; i<m_Directories.GetSize(); i++)
  392.   {
  393.     CHttpDirectory* pDir = m_Directories.GetAt(i);
  394.     delete pDir; 
  395.     pDir = NULL;
  396.   }
  397.   m_Directories.RemoveAll();
  398. }
  399. IMPLEMENT_DYNCREATE(CHttpDirectedThreadPoolQueue, CDirectedThreadPoolQueue)
  400. CHttpDirectedThreadPoolQueue::~CHttpDirectedThreadPoolQueue()
  401. {
  402.   //Before we are destroyed, deallocate any user requests
  403.   //which may still be lying around in the requests array
  404.   for (int i=0; i<m_Requests.GetSize(); i++)
  405.   {
  406.     CThreadPoolRequest& request = m_Requests.ElementAt(i);
  407.     if (request.m_dwID == THREADPOOL_USER_DEFINED_REQUEST)
  408.     {
  409.       CHttpThreadPoolRequest* pHttpRequest = (CHttpThreadPoolRequest*) request.m_pData;
  410.       delete pHttpRequest;
  411.       pHttpRequest = NULL;
  412.     }
  413.   }
  414. }
  415. IMPLEMENT_DYNAMIC(CHttpServer, CObject)
  416. CHttpServer::CHttpServer() : m_ListenStartEvent(TRUE), m_pListenThread(NULL), m_hImpersonation(NULL)
  417. {
  418. #ifndef W3MFC_NO_SSPI_SUPPORT
  419.   ZeroMemory(&m_hCredHandle, sizeof(m_hCredHandle));
  420. #endif
  421.   LoadHTMLResources();
  422. }
  423. void CHttpServer::LoadHTMLResources()
  424. {
  425.   m_psz302HTML = NULL;
  426.   m_dw302HTML = 0;
  427.   m_psz400HTML = NULL;
  428.   m_dw400HTML = 0;
  429.   m_psz401HTML = NULL;
  430.   m_dw401HTML = 0;
  431.   m_psz404HTML = NULL;
  432.   m_dw404HTML = 0;
  433.   m_psz500HTML = NULL;
  434.   m_dw500HTML = 0;
  435.   m_pszDeletedHTML = NULL;
  436.   m_dwDeletedHTML = 0;
  437.   LoadHTMLResource(IDH_302, m_psz302HTML, m_dw302HTML);
  438.   LoadHTMLResource(IDH_400, m_psz400HTML, m_dw400HTML);
  439.   LoadHTMLResource(IDH_401, m_psz401HTML, m_dw401HTML);
  440.   LoadHTMLResource(IDH_404, m_psz404HTML, m_dw404HTML);
  441.   LoadHTMLResource(IDH_500, m_psz500HTML, m_dw500HTML);
  442.   LoadHTMLResource(IDH_FILE_DELETED_OK, m_pszDeletedHTML, m_dwDeletedHTML);
  443. }
  444. CHttpServer::~CHttpServer()
  445. {
  446.   Stop();
  447.   FreeHTMLResources();
  448. }
  449. void CHttpServer::FreeHTMLResources()
  450. {
  451.   if (m_psz302HTML)
  452.   {
  453.     delete [] m_psz302HTML;
  454.     m_psz302HTML = NULL;
  455.     m_dw302HTML = 0;
  456.   }
  457.   if (m_psz400HTML)
  458.   {
  459.     delete [] m_psz400HTML;
  460.     m_psz400HTML = NULL;
  461.     m_dw400HTML = 0;
  462.   }
  463.   if (m_psz401HTML)
  464.   {
  465.     delete [] m_psz401HTML;
  466.     m_psz401HTML = NULL;
  467.     m_dw401HTML = 0;
  468.   }
  469.   if (m_psz404HTML)
  470.   {
  471.     delete [] m_psz404HTML;
  472.     m_psz404HTML = NULL;
  473.     m_dw404HTML = 0;
  474.   }
  475.   if (m_psz500HTML)
  476.   {
  477.     delete [] m_psz500HTML;
  478.     m_psz500HTML = NULL;
  479.     m_dw500HTML = 0;
  480.   }
  481.   if (m_pszDeletedHTML)
  482.   {
  483.     delete [] m_pszDeletedHTML;
  484.     m_pszDeletedHTML = NULL;
  485.     m_dwDeletedHTML = 0;
  486.   }
  487. }
  488. #ifndef W3MFC_NO_SSPI_SUPPORT
  489. BOOL CHttpServer::AcquireSSPI()
  490. {
  491.   //Get a connection to SSPI
  492.   TimeStamp tsExpires;
  493.   SECURITY_STATUS ss = AcquireCredentialsHandle(NULL, _T("NTLM"), SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &m_hCredHandle, &tsExpires);
  494.   BOOL bSuccess = (ss == SEC_E_OK);
  495.   //Report the error
  496.   if (!bSuccess)
  497.   {
  498.     CString sError;
  499.     sError.Format(_T("CHttpServer::AcquireSSPI, Failed in call to AcquireCredentialsHandle, Error:%d"), ss);
  500.     OnError(sError);
  501.   }
  502.   return bSuccess;
  503. }
  504. void CHttpServer::ReleaseSSPI()
  505. {
  506.   SECURITY_STATUS ss = FreeCredentialsHandle(&m_hCredHandle);
  507.   if (ss != SEC_E_OK)
  508.   {
  509.     CString sError;
  510.     sError.Format(_T("CHttpServer::ReleaseSSPI, Failed in call to FreeCredentialsHandle, Error:%d"), ss);
  511.     OnError(sError);
  512.   }
  513. }
  514. #endif
  515. BOOL CHttpServer::Start(CHttpServerSettings* pSettings)
  516. {
  517.   CSingleLock sl(&m_csListenThread, TRUE); //synchronize access to the listening thread
  518.   ASSERT(m_pListenThread == NULL); //Trying to start an already started server
  519.   ASSERT(pSettings);
  520.   ASSERT(pSettings->m_pMimeManager); //must be assigned before you call this function
  521. #ifndef W3MFC_NO_ISAPI_SUPPORT
  522.   ASSERT(pSettings->m_pISAPIManager); //must be assigned before you call this function
  523.   ASSERT(pSettings->m_pISAPI); //must be assigned before you call this function
  524.   pSettings->m_pISAPI->SetServer(this);
  525. #endif
  526. #ifndef W3MFC_NO_CGI_SUPPORT
  527.   ASSERT(pSettings->m_pCGI); //must be assigned before you call this function
  528. #endif
  529.   //Initialize SSPI
  530. #ifndef W3MFC_NO_SSPI_SUPPORT
  531.   if (!AcquireSSPI())
  532.     return FALSE;
  533. #endif
  534.   //Start the listener thread
  535.   m_pSettings = pSettings;
  536.   m_bListenerRunningOK = FALSE;
  537.   m_StopEvent.ResetEvent();
  538.   m_ListenStartEvent.ResetEvent();
  539.   m_pListenThread = AfxBeginThread(ListenSocketFunction, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
  540.   if (m_pListenThread == NULL)
  541.   {
  542.     //Report the error
  543.     CString sError;
  544.     sError.Format(_T("CHttpServer::Start, Failed to call to create listener thread, please check settings"));
  545.     OnError(sError);
  546.     return FALSE;
  547.   }
  548.   m_pListenThread->m_bAutoDelete = FALSE;
  549.   m_pListenThread->ResumeThread();
  550.   //Wait until the thread has completely started and return the success indicator
  551.   ::WaitForSingleObject(m_ListenStartEvent, INFINITE);
  552.   return m_bListenerRunningOK;
  553. }
  554. BOOL CHttpServer::Wait()
  555. {
  556.   CSingleLock sl(&m_csListenThread, TRUE); //synchronize access to the listening thread
  557.   //If the listener thread is running, then just wait for it to exit
  558.   if (m_pListenThread)
  559.   {
  560.     ::WaitForSingleObject(m_pListenThread->m_hThread, INFINITE);
  561.     delete m_pListenThread;
  562.     m_pListenThread = NULL;
  563.     return TRUE;
  564.   }
  565.   else
  566.   {
  567.     //Report the error
  568.     CString sError;
  569.     sError.Format(_T("CHttpServer::Wait, Http server is not running, so no need to wait"));
  570.     OnError(sError);
  571.     return FALSE;
  572.   }
  573. }
  574. BOOL CHttpServer::Stop()
  575. {
  576.   //Signal the listener thread to stop and wait for it to do so, Note that we do 
  577.   //this before we enter the critical section because otherwise we could end
  578.   //up in a deadlock situation between this function and Wait
  579.   m_StopEvent.SetEvent();
  580.   CSingleLock sl(&m_csListenThread, TRUE); //synchronize access to the listening thread
  581.   //If the listener thread is running, then stop it
  582.   if (m_pListenThread)
  583.   {
  584.     ::WaitForSingleObject(m_pListenThread->m_hThread, INFINITE);
  585.     delete m_pListenThread;
  586.     m_pListenThread = NULL;
  587.     //Release SSPI
  588. #ifndef W3MFC_NO_SSPI_SUPPORT
  589.     ReleaseSSPI();
  590. #endif
  591.   }
  592.   return TRUE;
  593. }
  594. BOOL CHttpServer::ReverseDNSLookup(in_addr sin_addr, CString& sDomainName)
  595. {
  596.   BOOL bSuccess = FALSE;
  597.   HOSTENT* pHostEnt = gethostbyaddr((const char*) &sin_addr, sizeof(sin_addr), AF_INET); 
  598.   if (pHostEnt)
  599.   {
  600.     bSuccess = TRUE;
  601.     sDomainName = pHostEnt->h_name;
  602.   }
  603.   return bSuccess;
  604. }
  605. #ifdef W3MFC_SSL_SUPPORT
  606. void CHttpServer::LogSSLErrors()
  607. {
  608.   char sError[1024];
  609.   unsigned long nError;
  610.   do
  611.   { 
  612.     nError = ERR_get_error();
  613.     if (nError)
  614.     {
  615.       ERR_error_string(nError, sError);
  616.       OnError(sError);
  617.     }
  618.   }
  619.   while (nError);
  620. }
  621. #endif
  622. CString CHttpServer::ErrorString()
  623. {
  624. DWORD err = ::GetLastError();
  625. CString Error;
  626. LPTSTR s;
  627. if(::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  628. FORMAT_MESSAGE_FROM_SYSTEM,
  629. NULL,
  630. err,
  631. 0x0409,
  632. (LPTSTR)&s,
  633. 0,
  634. NULL) == 0)
  635.     { /* failed */
  636. // Unknown error code %08x (%d)
  637. CString fmt;
  638. CString t;
  639. fmt.LoadString(IDS_UNKNOWN_ERROR);
  640. t.Format(fmt, err, LOWORD(err));
  641. Error = t;
  642.     } /* failed */
  643. else
  644.     { /* success */
  645. LPTSTR p = _tcschr(s, _T('r'));
  646. if(p != NULL)
  647.         { /* lose CRLF */
  648. *p = _T('');
  649.         } /* lose CRLF */
  650. Error = s;
  651. ::LocalFree(s);
  652.     } /* success */
  653. return Error;
  654. }
  655.                                
  656. void CHttpServer::ListenSocketFunction()
  657. {
  658.   USES_CONVERSION;
  659.   //Setup the thread pool 
  660.   ASSERT(m_pSettings);
  661.   ASSERT(m_pSettings->m_pRuntimeClientClass);
  662.   if (!m_ThreadPool.Start(m_pSettings->m_pRuntimeClientClass, m_pSettings->m_bUseIOCPQueue ? RUNTIME_CLASS(CIOCPThreadPoolQueue) : RUNTIME_CLASS(CHttpDirectedThreadPoolQueue), 
  663.                           m_pSettings->m_nThreadPoolSize, m_pSettings->m_nThreadPoolSize, TRUE))
  664.   {
  665.     //Report the error
  666.     CString sError;
  667.     sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to create thread pool, GetLastError:%d"), ::GetLastError());
  668.     OnError(sError);
  669.     m_ListenStartEvent.SetEvent();
  670.     return;
  671.   }
  672.   //Setup the pointers in the thread pool instances and resume the threads
  673.   for (int i=0; i<m_pSettings->m_nThreadPoolSize; i++)
  674.   {
  675.     CHttpClient* pClient = (CHttpClient*) m_ThreadPool.GetAtClient(i);
  676.     ASSERT(pClient);
  677.     ASSERT(pClient->IsKindOf(RUNTIME_CLASS(CHttpClient)));
  678.     pClient->m_pServer = this;
  679.     pClient->m_pWorkerThread->ResumeThread();
  680.   }
  681.   //Setup the recycling of threads
  682.   if (!m_ThreadPool.SetMaxThreadClientLifetime(m_pSettings->m_bEnableThreadLifetime, m_pSettings->m_dwThreadLifetime))
  683.   {
  684.     //Report the error
  685.     CString sError;
  686.     sError.Format(_T("CHttpServer::ListenSocketFunction, Failed in call to m_ThreadPool.SetMaxThreadClientLifetime, GetLastError:%d"), GetLastError());
  687.     OnError(sError);
  688.     m_ListenStartEvent.SetEvent();
  689.     return;
  690.   }
  691.   //Create the server socket
  692.   CHttpSocket serverSocket;
  693.   try
  694.   {
  695.     serverSocket.Create();
  696.   }
  697.   catch(CWSocketException* pEx)
  698.   {
  699.     //Report the error
  700.     CString sError;
  701.     sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to create server socket, GetLastError:%d"), pEx->m_nError);
  702.     OnError(sError);
  703.     m_ListenStartEvent.SetEvent();
  704.     pEx->Delete();  
  705.     return;
  706.   }
  707.   //Bind the server socket
  708.   try
  709.   {
  710.     if (m_pSettings->m_bBind)
  711.       serverSocket.Bind(m_pSettings->m_nPort, m_pSettings->m_sBindAddress);
  712.     else
  713.       serverSocket.Bind(m_pSettings->m_nPort);
  714.   }
  715.   catch(CWSocketException* pEx)
  716.   {
  717.     //Report the error
  718.     CString sError;
  719.     sError.Format(_T("Error Code:%d  %s"), pEx->m_nError,  ErrorString());
  720.     OnError(sError);
  721.     m_ListenStartEvent.SetEvent();
  722.     pEx->Delete();  
  723.     return;
  724.   }
  725.   //Put the server socket in a listening state
  726.   try
  727.   {
  728.     serverSocket.Listen();
  729.   }
  730.   catch(CWSocketException* pEx)
  731.   {
  732.     //Report the error
  733.     CString sError;
  734.     sError.Format(_T("Error Code:%d  %s"), pEx->m_nError,  ErrorString());
  735.     OnError(sError);
  736.     m_ListenStartEvent.SetEvent();
  737.     pEx->Delete();
  738.     return;
  739.   }
  740.   //Run the server under a different account if configured to do so
  741.   BOOL bUseAccount = (m_pSettings->m_sUsername.GetLength() != 0);
  742.   CW32Handle hImpersonation;
  743.   BOOL bLoggedOn = FALSE;
  744.   BOOL bImpersonated = FALSE;
  745.   if (bUseAccount)
  746.   {
  747.     LPTSTR pszUser = m_pSettings->m_sUsername.GetBuffer(m_pSettings->m_sUsername.GetLength());
  748.     LPTSTR pszPassword = m_pSettings->m_sPassword.GetBuffer(m_pSettings->m_sPassword.GetLength());
  749.     HANDLE hRawImpersonation = NULL;
  750.     bLoggedOn = LogonUser(pszUser, NULL, pszPassword, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hImpersonation);
  751.     if (bLoggedOn)
  752.     {
  753.       hImpersonation.Attach(hRawImpersonation);
  754.       bImpersonated = ImpersonateLoggedOnUser(hImpersonation);
  755.     }
  756.     else
  757.     {
  758.       //Report the error
  759.       CString sError;
  760.       sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to logon using user name: %s, GetLastError:%d"), pszUser, ::GetLastError());
  761.       OnError(sError);
  762.     }
  763.     m_pSettings->m_sUsername.ReleaseBuffer();
  764.     m_pSettings->m_sPassword.ReleaseBuffer();
  765.     //Clear the password now that we are finished with it
  766.     m_pSettings->m_sPassword.Empty();
  767.   } 
  768.   m_hImpersonation = hImpersonation; 
  769.   //Handle the case if the impersonation failed
  770.   if (bUseAccount && !bImpersonated)
  771.   {
  772.     //Report the error
  773.     CString sError;
  774.     sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to impersonate using supplied user credentials"));
  775.     OnError(sError);
  776.     m_ListenStartEvent.SetEvent();
  777.     return;
  778.   }
  779.   //Initialize SSL context if required to do so
  780. #ifdef W3MFC_SSL_SUPPORT
  781.   //Initialize the PRNG in OpenSSL
  782.   if (m_pSettings->m_sSSLRandomnessFile.IsEmpty())
  783.   {
  784.     //Get the default rand file from OpenSSL
  785.     char sSSLFile[1024];
  786.     const char* pszRandFile = RAND_file_name(sSSLFile, sizeof(sSSLFile));
  787.     if (pszRandFile)
  788.       m_pSettings->m_sSSLRandomnessFile = pszRandFile;
  789.     else
  790.     {
  791.       //Report the error
  792.       CString sError;
  793.       sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to get the default RAND file from OpenSSL"));
  794.       OnError(sError);
  795.       LogSSLErrors();
  796.     }
  797.   }
  798.   RAND_load_file(T2A((LPTSTR)(LPCTSTR)m_pSettings->m_sSSLRandomnessFile), -1);
  799.   if (RAND_status() == 0)
  800.   {
  801.     //Report the error
  802.     CString sError;
  803.     sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to initialize the PRNG in OpenSSL"));
  804.     OnError(sError);
  805.     LogSSLErrors();
  806.     //Failing to initialize the PRNG is not considered critical for W3MFC
  807.   }
  808.   CSSLContext sslContext;
  809.   if (m_pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
  810.   {
  811.     //Pick the SSL protocol to use
  812.     SSL_METHOD* pSSLMethod = NULL;
  813.     switch (m_pSettings->m_SSLProtocol)
  814.     {
  815.       case CHttpServerSettings::SSL_V2:
  816.       {
  817.         pSSLMethod = SSLv23_server_method();
  818.         break;
  819.       }
  820.       case CHttpServerSettings::SSL_V3:
  821.       {
  822.         pSSLMethod = SSLv3_server_method();
  823.         break;
  824.       }
  825.       case CHttpServerSettings::SSL_V2_OR_V3:
  826.       {
  827.         pSSLMethod = SSLv23_server_method();
  828.         break;
  829.       }
  830.       case CHttpServerSettings::TLS_V1:
  831.       {
  832.         pSSLMethod = TLSv1_server_method();
  833.         break;
  834.       }
  835.       default:
  836.       {
  837.         ASSERT(FALSE);
  838.         break;
  839.       }
  840.     }
  841.     //Create the SSL context object
  842.     ASSERT(pSSLMethod != NULL);
  843.     SSL_CTX* pSSLContext = SSL_CTX_new(pSSLMethod);
  844.     if (pSSLContext == NULL) 
  845.     {
  846.       //Report the error
  847.       CString sError;
  848.       sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to create SSL context object"));
  849.       OnError(sError);
  850.       LogSSLErrors();
  851.       m_ListenStartEvent.SetEvent();
  852.       return;
  853.     }
  854.     else
  855.       sslContext.Attach(pSSLContext);
  856.     //Set the certificate to use
  857.     if (SSL_CTX_use_certificate_file(sslContext, T2A((LPTSTR) (LPCTSTR) m_pSettings->m_sServerCertificateFile), SSL_FILETYPE_PEM) != 1) 
  858.     {
  859.       //Report the error
  860.       CString sError;
  861.       sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to load up server certificate"));
  862.       OnError(sError);
  863.       LogSSLErrors();
  864.       m_ListenStartEvent.SetEvent();
  865.       return;
  866.     }
  867.     //Set the private key to use
  868.     if (SSL_CTX_use_PrivateKey_file(sslContext, m_pSettings->m_sPrivateKeyFile.GetLength() ? 
  869.                                     T2A((LPTSTR) (LPCTSTR) m_pSettings->m_sPrivateKeyFile) : 
  870.                                     T2A((LPTSTR) (LPCTSTR) m_pSettings->m_sServerCertificateFile), SSL_FILETYPE_PEM) != 1) 
  871.     {
  872.       //Report the error
  873.       CString sError;
  874.       sError.Format(_T("CHttpServer::ListenSocketFunction, Failed to load up private key"));
  875.       OnError(sError);
  876.       LogSSLErrors();
  877.       m_ListenStartEvent.SetEvent();
  878.       return;
  879.     }
  880.     //Check that we the private key is ok
  881.     if (SSL_CTX_check_private_key(sslContext) != 1) 
  882.     {
  883.       //Report the error
  884.       CString sError;
  885.       sError.Format(_T("CHttpServer::ListenSocketFunction, Private key does not match the certificate public key"));
  886.       OnError(sError);
  887.       LogSSLErrors();  
  888.       m_ListenStartEvent.SetEvent();
  889.       return;
  890.     }
  891.     //Set the SSL session settings
  892.     if (m_pSettings->m_bReuseSessions)
  893.     {
  894.       int nOldTimeout;
  895.       nOldTimeout = SSL_CTX_set_timeout(sslContext, m_pSettings->m_dwSSLSessionTimeout);
  896.     }
  897.     else
  898.       SSL_CTX_set_timeout(sslContext, 0);
  899.   }
  900. #endif
  901.   //Use a Win32 event notification on the server socket
  902.   int nError = WSAEventSelect(serverSocket, m_SocketEvent, FD_ACCEPT);
  903.   if (nError == SOCKET_ERROR)
  904.   {
  905.     DWORD dwError = ::GetLastError();
  906.     //Report the error
  907.     CString sError;
  908.     sError.Format(_T("CHttpServer::ListenSocketFunction, Failed in call to WSAEventSelect, GetLastError:%d"), dwError);
  909.     OnError(sError);
  910.     m_ListenStartEvent.SetEvent();
  911.     return;
  912.   }
  913.   //We're now ready for accepting client connections, inform
  914.   //the main thread that everthing is ok
  915.   m_bListenerRunningOK = TRUE;
  916.   m_ListenStartEvent.SetEvent();
  917.   //Create the wait handles array (used for waiting for an event)
  918.   HANDLE Handles[2];
  919.   Handles[0] = m_StopEvent;
  920.   Handles[1] = m_SocketEvent;
  921.   //Wait for any incoming connections and the signal to exit the thread m_ListenStopEvent
  922.   BOOL bWantStop = FALSE;
  923.   CThreadPoolQueue* pQueue = m_ThreadPool.GetQueue();
  924.   ASSERT(pQueue);
  925.   while (!bWantStop)
  926.   {
  927.     DWORD dwWait = WaitForMultipleObjects(2, (CONST HANDLE*) &Handles, FALSE, INFINITE);
  928.     int nSignaledHandle = dwWait - WAIT_OBJECT_0;
  929.     if (nSignaledHandle == 0) //It was the stop request
  930.       bWantStop = TRUE;
  931.     else if (nSignaledHandle == 1) //It was a socket event
  932.     {
  933.       CHttpThreadPoolRequest* pRequest = new CHttpThreadPoolRequest;  
  934.       try
  935.       {
  936. #ifdef W3MFC_SSL_SUPPORT
  937.         pRequest->m_pSSLContext = &sslContext;
  938. #endif
  939.         //Accept the client connection  
  940.         serverSocket.Accept(pRequest->m_ClientSocket, pRequest->m_ClientAddress);
  941.         //Let a thread pool client class instance handle the work
  942.         CThreadPoolRequest poolRequest;
  943.         poolRequest.m_dwID = 1;
  944.         poolRequest.m_pData = pRequest;  
  945.         pQueue->PostRequest(poolRequest);
  946.       }
  947.       catch(CWSocketException* pEx)
  948.       {
  949.         //Report the error
  950.         CString sError;
  951.         sError.Format(_T("CHttpServer::ListenSocketFunction, An error occurred accepting a client connection, GetLastError:%d"), pEx->m_nError);
  952.         OnError(sError);
  953.         pEx->Delete();
  954.       }
  955.     }
  956.   }
  957.   //Revert back to normal security settings
  958.   if (bUseAccount)
  959.   {
  960.     //Revert to the usual security settings
  961.     if (bImpersonated)
  962.       RevertToSelf();
  963.   }
  964.   //Bring down the thread pool
  965.   m_ThreadPool.Stop();
  966. }
  967. UINT CHttpServer::ListenSocketFunction(LPVOID pParam)
  968. {
  969.   //Get back the "this" pointer from the pParam parameter
  970.   CHttpServer* pServer = (CHttpServer*) pParam;
  971.   ASSERT(pServer);
  972.   ASSERT(pServer->IsKindOf(RUNTIME_CLASS(CHttpServer)));
  973.   //Call the run method of the CHttpServer instance
  974.   pServer->ListenSocketFunction();
  975. #ifdef W3MFC_SSL_SUPPORT
  976.   //cleanup SSL thread state
  977.   ERR_remove_state(0);
  978. #endif
  979.   //Return the thread exit code
  980.   return TRUE;
  981. }
  982. #ifdef _DEBUG
  983. void CHttpServer::OnError(const CString& sError) //To avoid level 4 warning in release
  984. #else
  985. void CHttpServer::OnError(const CString& /*sError*/)
  986. #endif
  987. {
  988. #ifdef _DEBUG
  989.   //The default is to just TRACE the details
  990.   TRACE(_T("%sn"), sError);
  991. #endif
  992. }
  993. BOOL CHttpServer::LoadHTMLResource(UINT nID, char*& pszHTML, DWORD& dwSize)
  994. {
  995.   BOOL bSuccess = FALSE;
  996.   HMODULE hModule = AfxFindResourceHandle(MAKEINTRESOURCE(nID), RT_HTML);
  997.   HRSRC hRsrc = ::FindResource(hModule, MAKEINTRESOURCE(nID), RT_HTML);
  998.   if (hRsrc)
  999.   {
  1000.     //Load up the resource
  1001.     dwSize = ::SizeofResource(hModule, hRsrc); 
  1002.     HGLOBAL hGlobal = ::LoadResource(hModule, hRsrc);
  1003.     //Allocate a new char array and copy the HTML resource into it 
  1004.     if (hGlobal)
  1005.     {
  1006.       pszHTML = new char[dwSize + 1];
  1007.       char* pszResource = (char*) ::LockResource(hGlobal);
  1008.       if (pszResource)
  1009.       {
  1010.         strncpy(pszHTML, pszResource, dwSize);
  1011.         pszHTML[dwSize] = _T('');
  1012.         bSuccess = TRUE;
  1013.       }
  1014.       else
  1015.       {
  1016.         //Report the error
  1017.         TRACE(_T("CHttpServer::LoadHTMLResource, Failed to load HTML resource, GetLastError:%dn"), GetLastError());
  1018.       }
  1019.     }
  1020.   }
  1021.   return bSuccess;
  1022. }
  1023. char* CHttpServer::LoadHTML(int nStatusCode, DWORD& dwSize)
  1024. {
  1025.   //What will be the return value
  1026.   char* pszHTML = NULL;
  1027.   dwSize = 0;
  1028.   switch(nStatusCode)
  1029.   {
  1030.     case 302:
  1031.     {
  1032.       pszHTML = m_psz302HTML;
  1033.       dwSize = m_dw302HTML;
  1034.       break;
  1035.     }
  1036.     case 400:
  1037.     {
  1038.       pszHTML = m_psz400HTML;
  1039.       dwSize = m_dw400HTML;
  1040.       break;
  1041.     }
  1042.     case 401:
  1043.     {
  1044.       pszHTML = m_psz401HTML;
  1045.       dwSize = m_dw401HTML;
  1046.       break;
  1047.     }
  1048.     case 404:
  1049.     {
  1050.       pszHTML = m_psz404HTML;
  1051.       dwSize = m_dw404HTML;
  1052.       break;
  1053.     }
  1054.     default:
  1055.     {
  1056.       pszHTML = m_psz500HTML;
  1057.       dwSize = m_dw500HTML;
  1058.       break;
  1059.     }
  1060.   }
  1061.   return pszHTML;
  1062. }
  1063. char* CHttpServer::GetFileDeletedHTML(DWORD& dwSize)
  1064. {
  1065.   dwSize = m_dwDeletedHTML;
  1066.   return m_pszDeletedHTML;
  1067. }