Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3848 lines
107 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. server.cpp
  5. Abstract:
  6. This file implements the BITS server extensions
  7. --*/
  8. #include "precomp.h"
  9. #if DBG
  10. #define CLEARASYNCBUFFERS
  11. #endif
  12. typedef StringHandleW HTTPStackStringHandle;
  13. #define HTTP_STRING( X ) L ## X
  14. #define INTERNET_MAX_URL_LENGTH 2200
  15. const DWORD SERVER_REQUEST_SPINLOCK = 0x80000040;
  16. const DWORD ASYNC_READER_SPINLOCK = 0x80000040;
  17. const char * const UPLOAD_PROTOCOL_STRING_V1 = "{7df0354d-249b-430f-820d-3d2a9bef4931}";
  18. // packet types that are sent in the protocol
  19. const char * const PACKET_TYPE_CREATE_SESSION = "Create-Session";
  20. const char * const PACKET_TYPE_FRAGMENT = "Fragment";
  21. const char * const PACKET_TYPE_CLOSE_SESSION = "Close-Session";
  22. const char * const PACKET_TYPE_CANCEL_SESSION = "Cancel-Session";
  23. const char * const PACKET_TYPE_PING = "Ping";
  24. //
  25. // IISLogger
  26. //
  27. // Manages the circular debugging log.
  28. //
  29. class IISLogger
  30. {
  31. EXTENSION_CONTROL_BLOCK *m_ExtensionControlBlock;
  32. void LogString( const char *String, int Size );
  33. public:
  34. IISLogger( EXTENSION_CONTROL_BLOCK *ExtensionControlBlock ) :
  35. m_ExtensionControlBlock( ExtensionControlBlock )
  36. {
  37. }
  38. void LogError( ServerException Error );
  39. void LogError( const GUID & SessionID, ServerException Error );
  40. void LogNewSession( const GUID & SessionID );
  41. void LogUploadComplete( const GUID & SessionID, UINT64 FileSize );
  42. void LogSessionClose( const GUID & SessionID );
  43. void LogSessionCancel( const GUID & SessionID );
  44. void LogExecuteEnabled();
  45. };
  46. class CriticalSectionLock
  47. {
  48. CRITICAL_SECTION* m_cs;
  49. public:
  50. CriticalSectionLock( CRITICAL_SECTION *cs ) :
  51. m_cs( cs )
  52. {
  53. EnterCriticalSection( m_cs );
  54. }
  55. ~CriticalSectionLock()
  56. {
  57. LeaveCriticalSection( m_cs );
  58. }
  59. };
  60. class AsyncReader;
  61. struct STATE_FILE_STRUCT
  62. {
  63. UINT StateVersion;
  64. UINT64 UploadFileSize;
  65. BOOL NotifyCached;
  66. DWORD HttpCode;
  67. BOOL ReplyURLReturned;
  68. CHAR ReplyURL[ INTERNET_MAX_URL_LENGTH + 1 ];
  69. void Initialize()
  70. {
  71. StateVersion = STATE_FILE_VERSION;
  72. UploadFileSize = 0;
  73. NotifyCached = FALSE;
  74. ReplyURLReturned = FALSE;
  75. }
  76. };
  77. //
  78. // ServerRequest
  79. //
  80. // Contains all data needed to service a request. A request is a single POST not a single
  81. // upload.
  82. class ServerRequest : IISLogger
  83. {
  84. public:
  85. ServerRequest( EXTENSION_CONTROL_BLOCK * ExtensionControlBlock );
  86. ~ServerRequest();
  87. long AddRef();
  88. long Release();
  89. bool IsPending() { return m_IsPending; }
  90. // The do it function!
  91. void DispatchRequest();
  92. friend AsyncReader;
  93. private:
  94. long m_refs;
  95. CRITICAL_SECTION m_cs;
  96. bool m_IsPending;
  97. EXTENSION_CONTROL_BLOCK *m_ExtensionControlBlock;
  98. AsyncReader *m_AsyncReader;
  99. HANDLE m_ImpersonationToken; // Do not free this
  100. // Filled in by dispatch Request
  101. StringHandle m_PacketType;
  102. // Variables filled in by GeneratePhysicalPaths
  103. StringHandle m_DestinationDirectory;
  104. StringHandle m_DestinationFile;
  105. StringHandle m_ResponseDirectory;
  106. StringHandle m_ResponseFile;
  107. StringHandle m_RequestDirectory;
  108. StringHandle m_RequestFile;
  109. StringHandle m_StateFile;
  110. // Filled in by OpenCacheFile
  111. HANDLE m_CacheFile;
  112. // Filed in by OpenStateFile
  113. STATE_FILE_STRUCT *m_StateFileStruct;
  114. GUID m_SessionId;
  115. StringHandle m_SessionIdString;
  116. SmartVDirConfig m_DirectoryConfig;
  117. DWORD m_URLDepth;
  118. void GetConfig();
  119. StringHandle GetServerVariable( char *ServerVariable );
  120. bool TestServerVariable( char *ServerVariable );
  121. StringHandle GetRequestURL();
  122. void ValidateProtocol();
  123. void CrackSessionId();
  124. void GeneratePhysicalPaths();
  125. CHAR *BasePathOf(const CHAR *pPath);
  126. StringHandle GeneratePathInDestinationDir(LPCSTR szOriginalPath);
  127. HANDLE CreateFileWithDestinationAcls(const CHAR *szOriginalFile, DWORD fOnlyCreateNew, DWORD dwAttributes);
  128. void OpenStateFile();
  129. void CloseStateFile();
  130. void VerifySessionExists();
  131. void CheckFilesystemAccess();
  132. void OpenCacheFile();
  133. void ReopenCacheFileAsSync();
  134. void CloseCacheFile();
  135. void CrackContentRange(
  136. UINT64 & RangeStart,
  137. UINT64 & RangeLength,
  138. UINT64 & TotalLength );
  139. void ScheduleAsyncOperation(
  140. DWORD OperationID,
  141. LPVOID Buffer,
  142. LPDWORD Size,
  143. LPDWORD DataType );
  144. void CloseCancelSession();
  145. // dispatch routines
  146. void CreateSession();
  147. void AddFragment();
  148. void CloseSession();
  149. void CancelSession();
  150. void Ping();
  151. // Response handling
  152. void SendResponse( char *Format, DWORD Code = 200, ... );
  153. void SendResponse( ServerException Exception );
  154. void FinishSendingResponse();
  155. void DrainFragmentBlockComplete( DWORD cbIO, DWORD dwError );
  156. static void DrainFragmentBlockCompleteWrapper(
  157. LPEXTENSION_CONTROL_BLOCK lpECB,
  158. PVOID pContext,
  159. DWORD cbIO,
  160. DWORD dwError);
  161. void StartDrainBlock( );
  162. void DrainData();
  163. StringHandle m_ResponseString;
  164. DWORD m_ResponseCode;
  165. HRESULT m_ResponseHRESULT;
  166. UINT64 m_BytesToDrain;
  167. UINT64 m_ContentLength;
  168. // async IO handling
  169. void CompleteIO( AsyncReader *Reader, UINT64 TotalBytesRead );
  170. void HandleIOError( AsyncReader *Reader, ServerException Error, UINT64 TotalBytesRead );
  171. // backend notification
  172. char m_NotifyBuffer[ 1024 ];
  173. void SendResponseAfterNotification( DWORD HttpStatus, UINT64 RequestFileSize, const CHAR * ReplyURL );
  174. DWORD GetStatusCode( HINTERNET hRequest );
  175. void CallServerNotification( UINT64 CacheFileSize );
  176. bool TestResponseHeader( HINTERNET hRequest, const WCHAR *Header );
  177. StringHandle GetResponseHeader( HINTERNET hRequest, const WCHAR *Header );
  178. // deal with chaining
  179. static void ForwardComplete(
  180. LPEXTENSION_CONTROL_BLOCK lpECB, PVOID pContext,
  181. DWORD cbIO, DWORD dwError );
  182. void ForwardToNextISAPI();
  183. };
  184. // AsyncReader
  185. //
  186. // Manages the buffering needed to handle the async read/write operations.
  187. class AsyncReader : private OVERLAPPED
  188. {
  189. public:
  190. AsyncReader( ServerRequest *Request,
  191. UINT64 BytesToDrain,
  192. UINT64 BytesToWrite,
  193. UINT64 WriteOffset,
  194. HANDLE WriteHandle,
  195. char *PrereadBuffer,
  196. DWORD PrereadSize );
  197. ~AsyncReader();
  198. UINT64 GetWriteOffset()
  199. {
  200. return m_WriteOffset;
  201. }
  202. private:
  203. ServerRequest *m_Request;
  204. UINT64 m_BytesToDrain;
  205. UINT64 m_WriteOffset;
  206. UINT64 m_ReadOffset;
  207. UINT64 m_BytesToWrite;
  208. UINT64 m_BytesToRead;
  209. char * m_PrereadBuffer;
  210. DWORD m_PrereadSize;
  211. UINT64 m_TotalBytesRead;
  212. HANDLE m_WriteHandle;
  213. HANDLE m_ThreadToken;
  214. char m_OperationsPending;
  215. DWORD m_ReadBuffer;
  216. DWORD m_WriteBuffer;
  217. DWORD m_BuffersToWrite;
  218. bool m_WritePending;
  219. bool m_ReadPending;
  220. bool m_ErrorValid;
  221. ServerException m_Error;
  222. const static NUMBER_OF_IO_BUFFERS = 3;
  223. struct IOBuffer
  224. {
  225. UINT64 m_BufferWriteOffset;
  226. DWORD m_BufferUsed;
  227. char m_Buffer[ 32768 ];
  228. } m_IOBuffers[ NUMBER_OF_IO_BUFFERS ];
  229. void HandleError( ServerException Error );
  230. void CompleteIO();
  231. void StartReadRequest();
  232. void StartWriteRequest();
  233. void StartupIO( );
  234. void WriteComplete( DWORD dwError, DWORD BytesWritten );
  235. void ReadComplete( DWORD dwError, DWORD BytesRead );
  236. static DWORD StartupIOWraper( LPVOID Context );
  237. static void CALLBACK WriteCompleteWraper( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped );
  238. static void WINAPI ReadCompleteWraper( LPEXTENSION_CONTROL_BLOCK, PVOID pContext, DWORD cbIO, DWORD dwError );
  239. };
  240. ServerRequest::ServerRequest(
  241. EXTENSION_CONTROL_BLOCK * ExtensionControlBlock
  242. ) :
  243. IISLogger( ExtensionControlBlock ),
  244. m_refs(1),
  245. m_IsPending( false ),
  246. m_ExtensionControlBlock( ExtensionControlBlock ),
  247. m_AsyncReader( NULL ),
  248. m_ImpersonationToken( NULL ),
  249. m_StateFileStruct( NULL ),
  250. m_CacheFile( INVALID_HANDLE_VALUE ),
  251. m_DirectoryConfig( NULL ),
  252. m_ResponseCode( 0 ),
  253. m_ResponseHRESULT( 0 ),
  254. m_BytesToDrain( 0 ),
  255. m_ContentLength( 0 )
  256. {
  257. memset( &m_SessionId, 0, sizeof(m_SessionId) );
  258. if ( !InitializeCriticalSectionAndSpinCount( &m_cs, SERVER_REQUEST_SPINLOCK ) )
  259. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  260. }
  261. ServerRequest::~ServerRequest()
  262. {
  263. // The destructor handles most of the cleanup.
  264. Log( LOG_CALLEND, "Connection: %p, Packet-Type: %s, Method: %s, Path %s, HTTPError: %u, HRESULT: 0x%8.8X",
  265. m_ExtensionControlBlock->ConnID,
  266. (const char*)m_PacketType,
  267. m_ExtensionControlBlock->lpszMethod,
  268. m_ExtensionControlBlock->lpszPathTranslated,
  269. m_ResponseCode,
  270. m_ResponseHRESULT );
  271. delete m_AsyncReader;
  272. CloseCacheFile();
  273. CloseStateFile();
  274. m_DirectoryConfig.Clear();
  275. DeleteCriticalSection( &m_cs );
  276. if ( m_IsPending )
  277. {
  278. Log( LOG_INFO, "Ending session" );
  279. (*m_ExtensionControlBlock->ServerSupportFunction)
  280. ( m_ExtensionControlBlock->ConnID,
  281. HSE_REQ_DONE_WITH_SESSION,
  282. NULL,
  283. NULL,
  284. NULL );
  285. }
  286. }
  287. long
  288. ServerRequest::AddRef()
  289. {
  290. long Result = InterlockedIncrement( &m_refs );
  291. ASSERT( Result > 0 );
  292. return Result;
  293. }
  294. long
  295. ServerRequest::Release()
  296. {
  297. long Result = InterlockedDecrement( &m_refs );
  298. ASSERT( Result >= 0 );
  299. if ( !Result )
  300. delete this;
  301. return Result;
  302. }
  303. StringHandle
  304. ServerRequest::GetServerVariable(
  305. char * ServerVariable )
  306. {
  307. //
  308. // Retrive a server variable from IIS. Throws an exception
  309. // is the variable can not be retrieved.
  310. //
  311. DWORD SizeOfBuffer = 0;
  312. BOOL Result = (*m_ExtensionControlBlock->GetServerVariable)
  313. ( m_ExtensionControlBlock->ConnID,
  314. ServerVariable,
  315. NULL,
  316. &SizeOfBuffer );
  317. if ( Result )
  318. return StringHandle();
  319. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  320. {
  321. Log( LOG_ERROR, "Unable to lookup server variable %s, error %x",
  322. ServerVariable,
  323. HRESULT_FROM_WIN32( GetLastError() ) );
  324. throw ServerException( HRESULT_FROM_WIN32(GetLastError()) );
  325. }
  326. if ( SizeOfBuffer > BITS_MAX_HEADER_SIZE )
  327. {
  328. Log( LOG_ERROR, "Variable is larger then the maximum size" );
  329. throw ServerException( E_INVALIDARG );
  330. }
  331. StringHandle WorkString;
  332. char *Buffer = WorkString.AllocBuffer( SizeOfBuffer );
  333. Result = (*m_ExtensionControlBlock->GetServerVariable)
  334. ( m_ExtensionControlBlock->ConnID,
  335. ServerVariable,
  336. Buffer,
  337. &SizeOfBuffer );
  338. if ( !Result )
  339. {
  340. Log( LOG_ERROR, "Unable to lookup server variable %s, error %x",
  341. ServerVariable,
  342. HRESULT_FROM_WIN32( GetLastError() ) );
  343. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  344. }
  345. WorkString.SetStringSize();
  346. return WorkString;
  347. }
  348. bool
  349. ServerRequest::TestServerVariable(
  350. char *ServerVariable )
  351. {
  352. // Test for the existence of a server variable.
  353. // Returns true if the variable exists, and false if it doesn't.
  354. // throw an exception on an error.
  355. DWORD SizeOfBuffer = 0;
  356. BOOL Result = (*m_ExtensionControlBlock->GetServerVariable)
  357. ( m_ExtensionControlBlock->ConnID,
  358. ServerVariable,
  359. NULL,
  360. &SizeOfBuffer );
  361. if ( Result )
  362. return true;
  363. DWORD dwError = GetLastError();
  364. if ( ERROR_INVALID_INDEX == dwError ||
  365. ERROR_NO_DATA == dwError )
  366. return false;
  367. if ( ERROR_INSUFFICIENT_BUFFER == dwError )
  368. return true;
  369. Log( LOG_ERROR, "Unable to test server variable %s, error %x",
  370. ServerVariable,
  371. HRESULT_FROM_WIN32( GetLastError() ) );
  372. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  373. }
  374. StringHandle
  375. ServerRequest::GetRequestURL()
  376. {
  377. // Recreate the request URL from the information available from IIS.
  378. // This may not always be possible, but do the best that we can do.
  379. StringHandle ServerName = GetServerVariable("SERVER_NAME");
  380. StringHandle ServerPort = GetServerVariable("SERVER_PORT");
  381. StringHandle URL = GetServerVariable("URL");
  382. StringHandle HTTPS = GetServerVariable("HTTPS");
  383. StringHandle QueryString = GetServerVariable("QUERY_STRING");
  384. StringHandle RequestURL;
  385. if ( _stricmp( HTTPS, "on" ) == 0 )
  386. RequestURL = "https://";
  387. else
  388. RequestURL = "http://";
  389. RequestURL += ServerName;
  390. RequestURL += ":";
  391. RequestURL += ServerPort;
  392. RequestURL += URL;
  393. if ( QueryString.Size() > 0 )
  394. {
  395. RequestURL += "?";
  396. RequestURL += QueryString;
  397. }
  398. return BITSUrlCanonicalize( RequestURL, URL_ESCAPE_UNSAFE );
  399. }
  400. void
  401. ServerRequest::FinishSendingResponse()
  402. {
  403. // Completes the response. The response is taken from the buffer and
  404. // sent to the client via IIS. The choice to cancel or keep-alive the
  405. // connection made by IIS.
  406. Log( LOG_INFO, "Finish sending response" );
  407. // Close the cache and state files before sending the response in case the client starts a new request immediatly.
  408. CloseCacheFile();
  409. CloseStateFile();
  410. // Finish sending the response using the information
  411. // in m_ResponseBuffer and m_ResponseCode.
  412. // If an error occures, give up and force a disconnect.
  413. m_ExtensionControlBlock->dwHttpStatusCode = m_ResponseCode;
  414. BOOL Result;
  415. BOOL KeepConnection;
  416. Result =
  417. (m_ExtensionControlBlock->ServerSupportFunction)(
  418. m_ExtensionControlBlock->ConnID,
  419. HSE_REQ_IS_KEEP_CONN,
  420. &KeepConnection,
  421. NULL,
  422. NULL );
  423. if ( !Result )
  424. {
  425. // Error occured quering the disconnect setting. Assume
  426. // a disconnect.
  427. KeepConnection = 0;
  428. }
  429. // IIS5.0(Win2k) has a bug where KeepConnect is returned as -1
  430. // to keep the connection alive. Apparently, this confuses the
  431. // HSE_REQ_SEND_RESPONSE_HEADER_EX call. Bash the value into a real bool.
  432. KeepConnection = KeepConnection ? 1 : 0;
  433. HSE_SEND_HEADER_EX_INFO HeaderInfo;
  434. HeaderInfo.pszStatus = LookupHTTPStatusCodeText( m_ResponseCode );
  435. HeaderInfo.cchStatus = strlen( HeaderInfo.pszStatus );
  436. HeaderInfo.pszHeader = (const char*)m_ResponseString;
  437. HeaderInfo.cchHeader = (DWORD)m_ResponseString.Size();
  438. HeaderInfo.fKeepConn = KeepConnection;
  439. Result =
  440. (m_ExtensionControlBlock->ServerSupportFunction)(
  441. m_ExtensionControlBlock->ConnID,
  442. HSE_REQ_SEND_RESPONSE_HEADER_EX,
  443. &HeaderInfo,
  444. NULL,
  445. NULL );
  446. if ( !Result )
  447. {
  448. Log( LOG_ERROR, "Unable to send response, error %x",
  449. HRESULT_FROM_WIN32( GetLastError() ) );
  450. Log( LOG_INFO, "Forcing the connection closed" );
  451. // Couldn't send the response, attempt to close the connection
  452. Result =
  453. (m_ExtensionControlBlock->ServerSupportFunction)(
  454. m_ExtensionControlBlock->ConnID,
  455. HSE_REQ_CLOSE_CONNECTION,
  456. NULL,
  457. NULL,
  458. NULL );
  459. if ( !Result )
  460. {
  461. // The close connection request failed. No choice but to invoke
  462. // the hammer of death
  463. (m_ExtensionControlBlock->ServerSupportFunction)(
  464. m_ExtensionControlBlock->ConnID,
  465. HSE_REQ_ABORTIVE_CLOSE,
  466. NULL,
  467. NULL,
  468. NULL );
  469. }
  470. }
  471. }
  472. void
  473. ServerRequest::SendResponse( char *Format, DWORD Code, ...)
  474. {
  475. // Starts the sending of a response. Unfortunatly, many HTTP
  476. // client stacks do not handle a response being returned while
  477. // data is still being sent. To handle this, it is necessary
  478. // to capture the response to a buffer. Then after all the sent data
  479. // is drained, finally send the response.
  480. va_list arglist;
  481. va_start( arglist, Code );
  482. SIZE_T ResponseBufferSize = 512;
  483. while( 1 )
  484. {
  485. char * ResponseBuffer = m_ResponseString.AllocBuffer( ResponseBufferSize );
  486. HRESULT Hr =
  487. StringCchVPrintfA(
  488. ResponseBuffer,
  489. ResponseBufferSize,
  490. Format,
  491. arglist );
  492. if ( SUCCEEDED( Hr ) )
  493. {
  494. m_ResponseString.SetStringSize();
  495. break;
  496. }
  497. else if ( STRSAFE_E_INSUFFICIENT_BUFFER == Hr )
  498. ResponseBufferSize *= 2;
  499. else
  500. throw ServerException( Hr );
  501. if ( ResponseBufferSize >= 0xFFFFFFFF )
  502. throw ServerException( E_INVALIDARG );
  503. }
  504. m_ResponseCode = Code;
  505. if ( m_BytesToDrain )
  506. {
  507. // Drain the data first, then send the response.
  508. Log( LOG_INFO, "Draining data" );
  509. try
  510. {
  511. // start draining data. DrainData() calls FinishSendingResponse
  512. // when it is finished.
  513. DrainData();
  514. }
  515. catch( const ComError & )
  516. {
  517. // something is very broken, and an attempt to drain excess data
  518. // failed. Nothing else to do except try sending the response.
  519. FinishSendingResponse();
  520. }
  521. return;
  522. }
  523. else
  524. {
  525. // Just send the response since we already handled draining
  526. FinishSendingResponse();
  527. }
  528. }
  529. void
  530. ServerRequest::SendResponse( ServerException Exception )
  531. {
  532. // Starts the sending of a response. Unfortunatly, many HTTP
  533. // client stacks do not handle a response being returned while
  534. // data is still being sent. To handle this, it is necessary
  535. // to capture the response to a buffer. Then after all the sent data
  536. // is drained, finally send the response.
  537. GUID NullGuid;
  538. memset( &NullGuid, 0, sizeof( NullGuid ) );
  539. if ( memcmp( &NullGuid, &m_SessionId, sizeof( NullGuid ) ) == 0 )
  540. LogError( Exception );
  541. else
  542. LogError( m_SessionId, Exception );
  543. SIZE_T ResponseBufferSize = 512;
  544. while( 1 )
  545. {
  546. char * ResponseBuffer = m_ResponseString.AllocBuffer( ResponseBufferSize );
  547. HRESULT Hr =
  548. StringCchPrintfA(
  549. ResponseBuffer,
  550. ResponseBufferSize,
  551. "Pragma: no-cache\r\n"
  552. "BITS-packet-type: Ack\r\n"
  553. "BITS-Error: 0x%8.8X\r\n"
  554. "BITS-Error-Context: 0x%X\r\n"
  555. "Content-Length: 0\r\n"
  556. "\r\n",
  557. Exception.GetCode(),
  558. Exception.GetContext() );
  559. if ( SUCCEEDED( Hr ) )
  560. {
  561. m_ResponseString.SetStringSize();
  562. break;
  563. }
  564. else if ( STRSAFE_E_INSUFFICIENT_BUFFER == Hr )
  565. ResponseBufferSize *= 2;
  566. else
  567. throw ServerException( Hr );
  568. if ( ResponseBufferSize >= 0xFFFFFFFF )
  569. throw ServerException( E_INVALIDARG );
  570. }
  571. m_ResponseCode = Exception.GetHttpCode();
  572. m_ResponseHRESULT = Exception.GetCode();
  573. Log( LOG_INFO, "Sending error response of HRESULT: 0x%8.8X, HTTP status: %d",
  574. m_ResponseHRESULT, m_ResponseCode );
  575. try
  576. {
  577. DrainData();
  578. }
  579. catch( const ComError & )
  580. {
  581. FinishSendingResponse();
  582. }
  583. }
  584. void
  585. ServerRequest::DrainFragmentBlockComplete(
  586. DWORD cbIO,
  587. DWORD dwError )
  588. {
  589. // A drain block has been completed. If this is the last block, finish sending the response.
  590. // Otherwise,
  591. Log( LOG_INFO, "Drain fragment complete, cbIO: %u, dwError: %u", cbIO, dwError );
  592. m_BytesToDrain -= cbIO;
  593. if ( !m_BytesToDrain || !cbIO || dwError )
  594. {
  595. FinishSendingResponse();
  596. return;
  597. }
  598. try
  599. {
  600. StartDrainBlock();
  601. }
  602. catch( const ComError & )
  603. {
  604. // An error occured while draining data, exit
  605. FinishSendingResponse();
  606. }
  607. }
  608. void
  609. ServerRequest::DrainFragmentBlockCompleteWrapper(
  610. LPEXTENSION_CONTROL_BLOCK lpECB,
  611. PVOID pContext,
  612. DWORD cbIO,
  613. DWORD dwError)
  614. {
  615. // Wrapper, handles critical section
  616. ServerRequest *This = (ServerRequest*)pContext;
  617. {
  618. CriticalSectionLock CSLock( &This->m_cs );
  619. This->DrainFragmentBlockComplete( cbIO, dwError );
  620. }
  621. This->Release();
  622. }
  623. void
  624. ServerRequest::StartDrainBlock( )
  625. {
  626. // start the next block to drain.
  627. BOOL Result;
  628. static char s_Buffer[ 32768 ];
  629. DWORD ReadSize = (DWORD)min( 0xFFFFFFFF, min( m_BytesToDrain, sizeof( s_Buffer ) ) );
  630. DWORD Flags = HSE_IO_ASYNC;
  631. Log( LOG_INFO, "Starting next drain block of %u bytes", ReadSize );
  632. ScheduleAsyncOperation(
  633. HSE_REQ_ASYNC_READ_CLIENT,
  634. (LPVOID)s_Buffer,
  635. &ReadSize,
  636. &Flags );
  637. }
  638. void
  639. ServerRequest::DrainData()
  640. {
  641. // Make the decission regarding the amount of data to drain
  642. // and the start the first block
  643. if ( m_DirectoryConfig )
  644. m_BytesToDrain = min( m_BytesToDrain, m_DirectoryConfig->m_MaxFileSize );
  645. else
  646. // use an internal max of 4KB
  647. m_BytesToDrain = min( 4096, m_BytesToDrain );
  648. if ( !m_BytesToDrain )
  649. {
  650. Log( LOG_INFO, "No bytes to drain, finish it" );
  651. FinishSendingResponse();
  652. return;
  653. }
  654. Log( LOG_INFO, "Starting pipe drain" );
  655. BOOL Result;
  656. Result =
  657. (*m_ExtensionControlBlock->ServerSupportFunction)(
  658. m_ExtensionControlBlock->ConnID,
  659. HSE_REQ_IO_COMPLETION,
  660. (LPVOID)DrainFragmentBlockCompleteWrapper,
  661. 0,
  662. (LPDWORD)this );
  663. if ( !Result )
  664. {
  665. Log( LOG_ERROR, "Error settings callback, error %x",
  666. HRESULT_FROM_WIN32( GetLastError() ) );
  667. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  668. }
  669. StartDrainBlock();
  670. }
  671. void
  672. ServerRequest::ValidateProtocol()
  673. {
  674. // Negotiate the protocol with the client. The client sends a list of
  675. // supported protocols to the server and the server picks the best protocol.
  676. // For now, only one protocol is supported.
  677. StringHandle SupportedProtocolsHandle = GetServerVariable( "HTTP_BITS-SUPPORTED-PROTOCOLS" );
  678. WorkStringBuffer SupportedProtocolsBuffer( (const char*) SupportedProtocolsHandle );
  679. char *SupportedProtocols = SupportedProtocolsBuffer.GetBuffer();
  680. char *Protocol = strtok( SupportedProtocols, " ," );
  681. while( Protocol )
  682. {
  683. if ( _stricmp( Protocol, UPLOAD_PROTOCOL_STRING_V1 ) == 0 )
  684. {
  685. Log( LOG_INFO, "Detected protocol upload protocol V1" );
  686. return;
  687. }
  688. Protocol = strtok( NULL, " ," );
  689. }
  690. Log( LOG_INFO, "Unsupported protocols, %s", (const char*)SupportedProtocols );
  691. throw ServerException( E_INVALIDARG );
  692. }
  693. void
  694. ServerRequest::CrackSessionId()
  695. {
  696. // Convert the session ID from a string into a GUID.
  697. StringHandle SessionId = GetServerVariable( "HTTP_BITS-Session-Id" );
  698. m_SessionId = BITSGuidFromString( SessionId );
  699. m_SessionIdString = BITSStringFromGuid( m_SessionId );
  700. }
  701. void
  702. ServerRequest::CrackContentRange(
  703. UINT64 & RangeStart,
  704. UINT64 & RangeLength,
  705. UINT64 & TotalLength )
  706. {
  707. // Crack the content range header which contains the client's view of where the
  708. // upload is at.
  709. StringHandle ContentRange = GetServerVariable( "HTTP_Content-Range" );
  710. UINT64 RangeEnd;
  711. int ReturnVal = sscanf( ContentRange, " bytes %I64u - %I64u / %I64u ",
  712. &RangeStart, &RangeEnd, &TotalLength );
  713. if ( ReturnVal != 3 )
  714. {
  715. Log( LOG_ERROR, "Range has %d elements instead of the expected number of 3", ReturnVal );
  716. throw ServerException( E_INVALIDARG );
  717. }
  718. if ( TotalLength > m_DirectoryConfig->m_MaxFileSize )
  719. {
  720. Log( LOG_ERROR, "Size of the upload at %I64u is greater then the maximum of %I64u",
  721. TotalLength, m_DirectoryConfig->m_MaxFileSize );
  722. throw ServerException( BG_E_TOO_LARGE );
  723. }
  724. if ( ( RangeStart == RangeEnd + 1 ) &&
  725. ( 0 == m_ContentLength ) &&
  726. ( RangeStart == TotalLength ) )
  727. {
  728. // Continue after a failed notification
  729. RangeStart = TotalLength;
  730. RangeLength = 0;
  731. return;
  732. }
  733. if ( RangeEnd < RangeStart )
  734. {
  735. Log( LOG_ERROR, "Range start is greater then the range length, End %I64u, Start %I64u",
  736. RangeEnd, RangeStart );
  737. throw ServerException( E_INVALIDARG );
  738. }
  739. RangeLength = RangeEnd - RangeStart + 1;
  740. if ( m_ContentLength != RangeLength )
  741. {
  742. Log( LOG_ERROR, "The content length is different from the range length. Content %I64u, Range %I64u",
  743. m_ContentLength, RangeLength );
  744. throw ServerException( E_INVALIDARG );
  745. }
  746. }
  747. void
  748. ServerRequest::ScheduleAsyncOperation(
  749. DWORD OperationID,
  750. LPVOID Buffer,
  751. LPDWORD Size,
  752. LPDWORD DataType )
  753. {
  754. // start an async operation and handle all the flags and recounting required.
  755. BOOL Result;
  756. AddRef();
  757. Result =
  758. (*m_ExtensionControlBlock->ServerSupportFunction)(
  759. m_ExtensionControlBlock->ConnID,
  760. OperationID,
  761. Buffer,
  762. Size,
  763. DataType );
  764. if ( !Result )
  765. {
  766. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  767. Log( LOG_ERROR, "Error starting async operation, error %x", Hr );
  768. // Operation was never scheduled, remove the callbacks refcount
  769. Release();
  770. throw ServerException( Hr );
  771. }
  772. m_IsPending = true;
  773. }
  774. void
  775. ServerRequest::CloseStateFile()
  776. {
  777. if ( m_StateFileStruct )
  778. {
  779. UnmapViewOfFile( m_StateFileStruct );
  780. m_StateFileStruct = NULL;
  781. }
  782. }
  783. void
  784. ServerRequest::OpenStateFile()
  785. {
  786. HANDLE StateFileHandle = INVALID_HANDLE_VALUE;
  787. HANDLE FileMapping = NULL;
  788. try
  789. {
  790. StateFileHandle = CreateFileWithDestinationAcls( m_StateFile, FALSE, FILE_ATTRIBUTE_NORMAL );
  791. LARGE_INTEGER FileSize;
  792. if ( !GetFileSizeEx( StateFileHandle, &FileSize ) )
  793. {
  794. throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
  795. }
  796. if ( STATE_FILE_SIZE != FileSize.QuadPart )
  797. {
  798. if ( FileSize.QuadPart )
  799. {
  800. Log( LOG_WARNING, "State file is corrupt" );
  801. // Clear out the old file bytes
  802. if ( INVALID_SET_FILE_POINTER == SetFilePointer( StateFileHandle, 0, NULL, FILE_BEGIN ) )
  803. throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
  804. if ( !SetEndOfFile( StateFileHandle ) )
  805. throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
  806. }
  807. if ( INVALID_SET_FILE_POINTER == SetFilePointer( StateFileHandle, STATE_FILE_SIZE, NULL, FILE_BEGIN ) )
  808. throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
  809. // reextend the file
  810. if ( !SetEndOfFile( StateFileHandle ) )
  811. {
  812. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  813. Log( LOG_ERROR, "Unable to extend the state file, error %x", Hr );
  814. throw ComError( Hr );
  815. }
  816. }
  817. //
  818. // Map the state file
  819. //
  820. FileMapping =
  821. CreateFileMapping(
  822. StateFileHandle,
  823. NULL,
  824. PAGE_READWRITE,
  825. 0,
  826. 0,
  827. NULL );
  828. if ( !FileMapping )
  829. {
  830. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  831. Log( LOG_ERROR, "Unable to map the state file, error %x", Hr );
  832. throw ComError( Hr );
  833. }
  834. m_StateFileStruct =
  835. (STATE_FILE_STRUCT*)MapViewOfFile(
  836. FileMapping,
  837. FILE_MAP_ALL_ACCESS,
  838. 0,
  839. 0,
  840. 0 );
  841. if ( !m_StateFileStruct )
  842. throw ComError( HRESULT_FROM_WIN32( GetLastError() ) );
  843. if ( m_StateFileStruct->StateVersion != STATE_FILE_VERSION )
  844. m_StateFileStruct->Initialize();
  845. CloseHandle( FileMapping );
  846. CloseHandle( StateFileHandle );
  847. return;
  848. }
  849. catch( ComError Error )
  850. {
  851. if ( m_StateFileStruct )
  852. {
  853. UnmapViewOfFile( m_StateFileStruct );
  854. m_StateFileStruct = NULL;
  855. }
  856. if ( !FileMapping )
  857. CloseHandle( FileMapping );
  858. if ( INVALID_HANDLE_VALUE != StateFileHandle )
  859. CloseHandle( StateFileHandle );
  860. throw Error;
  861. }
  862. }
  863. // dispatch routines
  864. void
  865. ServerRequest::CreateSession()
  866. {
  867. // Handles the Create-Session command from the client.
  868. // Create a new session and all the directories required to
  869. // support that session.
  870. ValidateProtocol();
  871. m_SessionId = BITSCreateGuid();
  872. m_SessionIdString = BITSStringFromGuid( m_SessionId );
  873. GeneratePhysicalPaths();
  874. CheckFilesystemAccess();
  875. BITSCreateDirectory( (LPCTSTR)m_RequestDirectory );
  876. OpenStateFile();
  877. if ( m_DirectoryConfig->m_HostId.Size() )
  878. {
  879. if ( m_DirectoryConfig->m_HostIdFallbackTimeout != MD_BITS_NO_TIMEOUT )
  880. {
  881. SendResponse(
  882. "Pragma: no-cache\r\n"
  883. "BITS-Packet-Type: Ack\r\n"
  884. "BITS-Protocol: %s\r\n"
  885. "BITS-Session-Id: %s\r\n"
  886. "BITS-Host-Id: %s\r\n"
  887. "BITS-Host-Id-Fallback-Timeout: %u\r\n"
  888. "Content-Length: 0\r\n"
  889. "Accept-encoding: identity\r\n"
  890. "\r\n",
  891. 200,
  892. UPLOAD_PROTOCOL_STRING_V1,
  893. (const char*)m_SessionIdString, // SessionId
  894. (const char*)m_DirectoryConfig->m_HostId,
  895. m_DirectoryConfig->m_HostIdFallbackTimeout
  896. );
  897. }
  898. else
  899. {
  900. SendResponse(
  901. "Pragma: no-cache\r\n"
  902. "BITS-Packet-Type: Ack\r\n"
  903. "BITS-Protocol: %s\r\n"
  904. "BITS-Session-Id: %s\r\n"
  905. "BITS-Host-Id: %s\r\n"
  906. "Content-Length: 0\r\n"
  907. "Accept-encoding: identity\r\n"
  908. "\r\n",
  909. 200,
  910. UPLOAD_PROTOCOL_STRING_V1,
  911. (const char*)m_SessionIdString, // SessionId
  912. (const char*)m_DirectoryConfig->m_HostId
  913. );
  914. }
  915. }
  916. else
  917. {
  918. SendResponse(
  919. "Pragma: no-cache\r\n"
  920. "BITS-Packet-Type: Ack\r\n"
  921. "BITS-Protocol: %s\r\n"
  922. "BITS-Session-Id: %s\r\n"
  923. "Content-Length: 0\r\n"
  924. "Accept-encoding: identity\r\n"
  925. "\r\n",
  926. 200,
  927. UPLOAD_PROTOCOL_STRING_V1,
  928. (const char*)m_SessionIdString // SessionId
  929. );
  930. }
  931. LogNewSession( m_SessionId );
  932. }
  933. void
  934. ServerRequest::AddFragment()
  935. {
  936. // Handles the fragment command from the client. Opens the cache file
  937. // and resumes the upload.
  938. CrackSessionId();
  939. GeneratePhysicalPaths();
  940. VerifySessionExists();
  941. OpenStateFile();
  942. UINT64 RangeStart, RangeLength, TotalLength;
  943. CrackContentRange( RangeStart, RangeLength, TotalLength );
  944. if ( RangeStart + RangeLength > TotalLength )
  945. {
  946. Log( LOG_ERROR, "Range extends past end of file. Start %I64u, Length %I64u, Total %I64u",
  947. RangeStart, RangeLength, TotalLength );
  948. throw ServerException( E_INVALIDARG );
  949. }
  950. if ( m_StateFileStruct->UploadFileSize )
  951. {
  952. //
  953. // Check to make sure the client didn't try anything tricky and change the size of
  954. // the upload on the fly. If it did, its an error.
  955. //
  956. if ( m_StateFileStruct->UploadFileSize != TotalLength )
  957. {
  958. // The client is attempting to change the file size, throw an error
  959. Log( LOG_ERROR, "Client is attempting to change the file size from %I64u to %I64u",
  960. m_StateFileStruct->UploadFileSize, TotalLength );
  961. throw ComError( E_INVALIDARG );
  962. }
  963. }
  964. else
  965. m_StateFileStruct->UploadFileSize = TotalLength;
  966. if ( m_StateFileStruct->NotifyCached )
  967. {
  968. //
  969. // The backend was already notified with a reasonable error code.
  970. // No need to notify it again.
  971. //
  972. SendResponseAfterNotification(
  973. m_StateFileStruct->HttpCode,
  974. m_StateFileStruct->UploadFileSize,
  975. m_StateFileStruct->ReplyURLReturned ?
  976. m_StateFileStruct->ReplyURL : NULL );
  977. return;
  978. }
  979. CheckFilesystemAccess();
  980. OpenCacheFile();
  981. UINT64 CacheFileSize = BITSGetFileSize( m_CacheFile );
  982. if ( CacheFileSize < RangeStart )
  983. {
  984. // Can't recover from this error on the server since we have a gap.
  985. // Need to get the client to backup and start again.
  986. Log( LOG_INFO, "Client and server are hopelessly out of sync, sending the 416 error code" );
  987. SendResponse(
  988. "Pragma: no-cache\r\n"
  989. "BITS-Packet-Type: Ack\r\n"
  990. "BITS-Received-Content-Range: %I64u\r\n"
  991. "Content-Length: 0\r\n"
  992. "\r\n",
  993. 416,
  994. CacheFileSize );
  995. return;
  996. }
  997. BITSSetFilePointer( m_CacheFile, 0, FILE_END );
  998. // Some thought cases for these formulas.
  999. // 1. RangeLength = 0
  1000. // BytesToDrain will be 0 and BytesToWrite will be 0
  1001. // 2. RangeStart = CacheFileSize ( most common case )
  1002. // BytesToDrain will be 0, and BytesToWrite will be BytesToDrain
  1003. // 3. RangeStart < CacheFileSize
  1004. // BytesToDrain will be nonzero, and BytesToWrite will be the remainder.
  1005. UINT64 BytesToDrain = min( (CacheFileSize - RangeStart), RangeLength );
  1006. UINT64 BytesToWrite = RangeLength - BytesToDrain;
  1007. UINT64 WriteOffset = CacheFileSize;
  1008. // Start the async reader
  1009. m_AsyncReader =
  1010. new AsyncReader(
  1011. this,
  1012. BytesToDrain,
  1013. BytesToWrite, // bytes to write
  1014. WriteOffset, // write offset
  1015. m_CacheFile,
  1016. (char*)m_ExtensionControlBlock->lpbData,
  1017. m_ExtensionControlBlock->cbAvailable );
  1018. }
  1019. // async IO handling
  1020. void
  1021. ServerRequest::CompleteIO( AsyncReader *Reader, UINT64 TotalBytesRead )
  1022. {
  1023. //
  1024. // Called by the AsyncReader when the request finished successfully.
  1025. //
  1026. Log( LOG_INFO, "Async IO operation complete, finishing" );
  1027. try
  1028. {
  1029. if ( TotalBytesRead > m_BytesToDrain )
  1030. m_BytesToDrain = 0; // shouldn't happen, but just in case
  1031. else
  1032. m_BytesToDrain -= TotalBytesRead;
  1033. UINT64 CacheFileSize = BITSGetFileSize( m_CacheFile );
  1034. ASSERT( Reader->GetWriteOffset() == CacheFileSize );
  1035. bool IsLastBlock = ( CacheFileSize == m_StateFileStruct->UploadFileSize );
  1036. if ( IsLastBlock &&
  1037. BITS_NOTIFICATION_TYPE_NONE != m_DirectoryConfig->m_NotificationType )
  1038. {
  1039. CallServerNotification( CacheFileSize );
  1040. }
  1041. else
  1042. {
  1043. // No server notification to make
  1044. SendResponse(
  1045. "Pragma: no-cache\r\n"
  1046. "BITS-Packet-Type: Ack\r\n"
  1047. "Content-Length: 0\r\n"
  1048. "BITS-Received-Content-Range: %I64u\r\n"
  1049. "\r\n",
  1050. 200,
  1051. CacheFileSize );
  1052. }
  1053. if ( IsLastBlock && TotalBytesRead )
  1054. LogUploadComplete( m_SessionId, CacheFileSize );
  1055. }
  1056. catch( ServerException Error )
  1057. {
  1058. SendResponse( Error );
  1059. }
  1060. catch( ComError Error )
  1061. {
  1062. SendResponse( Error );
  1063. }
  1064. }
  1065. void
  1066. ServerRequest::HandleIOError( AsyncReader *Reader, ServerException Error, UINT64 TotalBytesRead )
  1067. {
  1068. //
  1069. // Called by AsyncReader when a fatal error occures in processing the request
  1070. //
  1071. Log( LOG_ERROR, "An error occured while handling the async IO" );
  1072. if ( TotalBytesRead > m_BytesToDrain )
  1073. m_BytesToDrain = 0; // shouldn't happen, but just in case
  1074. else
  1075. m_BytesToDrain -= TotalBytesRead;
  1076. SendResponse( Error );
  1077. }
  1078. void
  1079. ServerRequest::SendResponseAfterNotification(
  1080. DWORD HttpStatus,
  1081. UINT64 RequestFileSize,
  1082. const CHAR * ReplyURL )
  1083. {
  1084. if ( ReplyURL )
  1085. {
  1086. if ( 200 != HttpStatus )
  1087. {
  1088. SendResponse(
  1089. "Pragma: no-cache\r\n"
  1090. "BITS-Packet-Type: Ack\r\n"
  1091. "Content-Length: 0\r\n"
  1092. "BITS-Received-Content-Range: %I64u\r\n"
  1093. "BITS-Reply-URL: %s\r\n"
  1094. "BITS-Error-Context: 0x7\r\n"
  1095. "\r\n",
  1096. HttpStatus,
  1097. RequestFileSize,
  1098. ReplyURL );
  1099. }
  1100. else
  1101. {
  1102. SendResponse(
  1103. "Pragma: no-cache\r\n"
  1104. "BITS-Packet-Type: Ack\r\n"
  1105. "Content-Length: 0\r\n"
  1106. "BITS-Received-Content-Range: %I64u\r\n"
  1107. "BITS-Reply-URL: %s\r\n"
  1108. "\r\n",
  1109. HttpStatus,
  1110. RequestFileSize,
  1111. ReplyURL );
  1112. }
  1113. }
  1114. else
  1115. {
  1116. if ( 200 != HttpStatus )
  1117. {
  1118. SendResponse(
  1119. "Pragma: no-cache\r\n"
  1120. "BITS-Packet-Type: Ack\r\n"
  1121. "Content-Length: 0\r\n"
  1122. "BITS-Received-Content-Range: %I64u\r\n"
  1123. "BITS-Error-Context: 0x7\r\n"
  1124. "\r\n",
  1125. HttpStatus,
  1126. RequestFileSize );
  1127. }
  1128. else
  1129. {
  1130. SendResponse(
  1131. "Pragma: no-cache\r\n"
  1132. "BITS-Packet-Type: Ack\r\n"
  1133. "Content-Length: 0\r\n"
  1134. "BITS-Received-Content-Range: %I64u\r\n"
  1135. "\r\n",
  1136. HttpStatus,
  1137. RequestFileSize );
  1138. }
  1139. }
  1140. }
  1141. DWORD
  1142. ServerRequest::GetStatusCode( HINTERNET hRequest )
  1143. {
  1144. DWORD dwStatus;
  1145. DWORD dwLength = sizeof(dwStatus);
  1146. if (!WinHttpQueryHeaders(hRequest,
  1147. WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
  1148. WINHTTP_HEADER_NAME_BY_INDEX,
  1149. &dwStatus,
  1150. &dwLength,
  1151. NULL))
  1152. {
  1153. Log( LOG_ERROR, "WinHttpQueryHeaders failed, error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1154. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1155. }
  1156. return dwStatus;
  1157. }
  1158. void
  1159. ServerRequest::CallServerNotification( UINT64 CacheFileSize )
  1160. {
  1161. // Handles notifications and all the exciting pieces to it.
  1162. HRESULT hr;
  1163. HINTERNET hInternet = NULL;
  1164. HINTERNET hConnect = NULL;
  1165. HINTERNET hRequest = NULL;
  1166. HANDLE hResponseFile = INVALID_HANDLE_VALUE;
  1167. BOOL fDoResend = FALSE;
  1168. Log( LOG_INFO, "Calling backend notification, type %u",
  1169. m_DirectoryConfig->m_NotificationType );
  1170. try
  1171. {
  1172. BITSCreateDirectory( (LPCTSTR)m_ResponseDirectory );
  1173. if ( BITS_NOTIFICATION_TYPE_POST_BYVAL == m_DirectoryConfig->m_NotificationType )
  1174. {
  1175. // only create the response file if this is a byval notification
  1176. try
  1177. {
  1178. hResponseFile = CreateFileWithDestinationAcls( m_ResponseFile, TRUE, FILE_ATTRIBUTE_NORMAL);
  1179. }
  1180. catch (ComError Error)
  1181. {
  1182. HRESULT hr = Error.m_Hr;
  1183. Log( LOG_ERROR, "Unable to create the response file %s, error %x", (const char*)m_ResponseFile, hr );
  1184. throw ServerException(hr,0,0x7);
  1185. }
  1186. }
  1187. Log( LOG_INFO, "Connecting to backend for notification" );
  1188. hInternet = WinHttpOpen( BITS_AGENT_NAMEW,
  1189. WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
  1190. NULL,
  1191. NULL,
  1192. 0 );
  1193. if ( !hInternet )
  1194. {
  1195. hr = HRESULT_FROM_WIN32(GetLastError());
  1196. Log( LOG_ERROR, "WinHttpOpen failed, error %x", hr );
  1197. throw ServerException( hr, 0, 0x7 );
  1198. }
  1199. StringHandle RequestURL = GetRequestURL();
  1200. StringHandleW NotificationURL;
  1201. if ( m_DirectoryConfig->m_NotificationURL.Size() != 0 )
  1202. {
  1203. // if the a notification URL was set, then combine that URL with the original URL.
  1204. // Otherwise just use the original URL. This allows BITS to be used to call
  1205. // many arbitrary ASP pages.
  1206. NotificationURL = StringHandleW(
  1207. BITSUrlCombine( RequestURL, m_DirectoryConfig->m_NotificationURL,
  1208. URL_ESCAPE_UNSAFE ) );
  1209. }
  1210. else
  1211. {
  1212. NotificationURL = StringHandleW( RequestURL );
  1213. }
  1214. Log( LOG_INFO, "Request URL: %s", (const char*)StringHandle( RequestURL ) );
  1215. Log( LOG_INFO, "Notification URL: %s", (const char*)StringHandle( NotificationURL ) );
  1216. //
  1217. // Split the URL into server, path, name, and password components.
  1218. //
  1219. HTTPStackStringHandle HostName;
  1220. HTTPStackStringHandle UrlPath;
  1221. HTTPStackStringHandle UserName;
  1222. HTTPStackStringHandle Password;
  1223. URL_COMPONENTS UrlComponents;
  1224. ZeroMemory(&UrlComponents, sizeof(UrlComponents));
  1225. UrlComponents.dwStructSize = sizeof(UrlComponents);
  1226. UrlComponents.lpszHostName = HostName.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1227. UrlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH + 1;
  1228. UrlComponents.lpszUrlPath = UrlPath.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1229. UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH + 1;
  1230. UrlComponents.lpszUserName = UserName.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1231. UrlComponents.dwUserNameLength = INTERNET_MAX_URL_LENGTH + 1;
  1232. UrlComponents.lpszPassword = Password.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1233. UrlComponents.dwPasswordLength = INTERNET_MAX_URL_LENGTH + 1;
  1234. if ( !WinHttpCrackUrl( NotificationURL,
  1235. (DWORD)NotificationURL.Size(),
  1236. 0,
  1237. &UrlComponents ) )
  1238. {
  1239. hr = HRESULT_FROM_WIN32(GetLastError());
  1240. Log( LOG_ERROR, "WinHttpCrackURL failed, error %x", hr);
  1241. throw ServerException(hr,0,0x7);
  1242. }
  1243. HostName.SetStringSize();
  1244. UrlPath.SetStringSize();
  1245. UserName.SetStringSize();
  1246. Password.SetStringSize();
  1247. StringHandle QueryString = GetServerVariable( "QUERY_STRING" );
  1248. if ( QueryString.Size() )
  1249. {
  1250. UrlPath += HTTPStackStringHandle( StringHandle("?") );
  1251. UrlPath += HTTPStackStringHandle( QueryString );
  1252. }
  1253. if ( BITS_NOTIFICATION_TYPE_POST_BYREF == m_DirectoryConfig->m_NotificationType )
  1254. CloseCacheFile();
  1255. hConnect = WinHttpConnect( hInternet,
  1256. HostName,
  1257. UrlComponents.nPort,
  1258. 0 );
  1259. if ( !hConnect )
  1260. {
  1261. hr = HRESULT_FROM_WIN32(GetLastError());
  1262. Log( LOG_ERROR, "WinHttpConnect failed, error %x", hr );
  1263. throw ServerException(hr,0,0x7);
  1264. }
  1265. const WCHAR *AcceptTypes[] = { HTTP_STRING( "*/*" ), NULL };
  1266. hRequest = WinHttpOpenRequest( hConnect,
  1267. HTTP_STRING( "POST" ),
  1268. UrlPath,
  1269. HTTP_STRING( "HTTP/1.1" ),
  1270. NULL,
  1271. AcceptTypes,
  1272. WINHTTP_FLAG_ESCAPE_DISABLE_QUERY );
  1273. if ( !hRequest )
  1274. {
  1275. Log( LOG_ERROR, "WinHttpOpenRequest failed, error %x", HRESULT_FROM_WIN32( GetLastError() ) );
  1276. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1277. }
  1278. //
  1279. // The autologon policy for WinHttp is by default to not allow authenticated logon
  1280. // when it thinks the URL is directed to an machine on the internet. Sense this URL is
  1281. // specifically configured by the administrator, we will allways allow autologin.
  1282. //
  1283. // Note: WinHttp assumes any DNS name with a "dot" in it is an internet (vs. intranet)
  1284. // name.
  1285. //
  1286. DWORD dwPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
  1287. if (!WinHttpSetOption(hRequest,
  1288. WINHTTP_OPTION_AUTOLOGON_POLICY,
  1289. &dwPolicy,
  1290. sizeof(dwPolicy)) )
  1291. {
  1292. hr = HRESULT_FROM_WIN32(GetLastError());
  1293. Log( LOG_ERROR, "WinHttpSetOption(WINHTTP_OPTION_AUOTLOGON_POLICY) failed, error %x",hr);
  1294. throw ServerException(hr,0,0x7);
  1295. }
  1296. DWORD dwBufferTotal = (DWORD)CacheFileSize;
  1297. HTTPStackStringHandle AdditionalHeaders = HTTP_STRING( "BITS-Original-Request-URL: " );
  1298. AdditionalHeaders += HTTPStackStringHandle( RequestURL );
  1299. AdditionalHeaders += HTTP_STRING( "\r\n" );
  1300. if ( BITS_NOTIFICATION_TYPE_POST_BYREF == m_DirectoryConfig->m_NotificationType )
  1301. {
  1302. // Add the path to the request datafile name
  1303. AdditionalHeaders += HTTP_STRING( "BITS-Request-DataFile-Name: " );
  1304. AdditionalHeaders += HTTPStackStringHandle( m_RequestFile );
  1305. AdditionalHeaders += HTTP_STRING( "\r\n" );
  1306. // Add the path to where to place the response datafile name
  1307. AdditionalHeaders += HTTP_STRING( "BITS-Response-DataFile-Name: " );
  1308. AdditionalHeaders += HTTPStackStringHandle( m_ResponseFile );
  1309. AdditionalHeaders += HTTP_STRING( "\r\n" );
  1310. dwBufferTotal = 0;
  1311. }
  1312. if ( !WinHttpAddRequestHeaders( hRequest,
  1313. AdditionalHeaders,
  1314. (DWORD)AdditionalHeaders.Size(),
  1315. WINHTTP_ADDREQ_FLAG_ADD | WINHTTP_ADDREQ_FLAG_REPLACE ) )
  1316. {
  1317. Log( LOG_ERROR, "WinHttpAddRequestHeaders failed error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1318. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1319. }
  1320. //
  1321. // Go ahead and send the Request
  1322. // Note that for both BYVAL and BYREF cases we will first try without credentials (anonymous request)
  1323. // if we get a 401, then we will loop again and winhttp will take care of sending the credentials
  1324. // (autologon policy is set to low)
  1325. //
  1326. if ( dwBufferTotal )
  1327. {
  1328. //
  1329. // BY VAL case
  1330. //
  1331. Log(LOG_INFO, "Making HTTP request with Notification URL for BYVAL case");
  1332. do
  1333. {
  1334. Log( LOG_INFO, "Sending data..." );
  1335. fDoResend = FALSE;
  1336. if ( !WinHttpSendRequest( hRequest,
  1337. NULL,
  1338. 0,
  1339. NULL,
  1340. WINHTTP_NO_REQUEST_DATA,
  1341. dwBufferTotal,
  1342. 0 ) )
  1343. {
  1344. Log( LOG_ERROR, "WinHttpSendRequest failed error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1345. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1346. }
  1347. ReopenCacheFileAsSync();
  1348. SetFilePointer( m_CacheFile, 0, NULL, FILE_BEGIN );
  1349. DWORD BytesRead;
  1350. DWORD TotalRead = 0;
  1351. do
  1352. {
  1353. BOOL b;
  1354. if (!(b = ReadFile (m_CacheFile,
  1355. m_NotifyBuffer,
  1356. sizeof(m_NotifyBuffer),
  1357. &BytesRead,
  1358. NULL)))
  1359. {
  1360. Log( LOG_ERROR, "ReadFile failed, error %x",
  1361. HRESULT_FROM_WIN32( GetLastError() ) );
  1362. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1363. }
  1364. TotalRead += BytesRead;
  1365. if (BytesRead > 0)
  1366. {
  1367. DWORD BytesWritten;
  1368. DWORD TotalWritten = 0;
  1369. do
  1370. {
  1371. if (!(b = WinHttpWriteData( hRequest,
  1372. m_NotifyBuffer + TotalWritten,
  1373. BytesRead - TotalWritten,
  1374. &BytesWritten)))
  1375. {
  1376. Log( LOG_ERROR, "WinHttpWriteData failed, error %x",
  1377. HRESULT_FROM_WIN32( GetLastError() ) );
  1378. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1379. }
  1380. TotalWritten += BytesWritten;
  1381. } while( TotalWritten != BytesRead );
  1382. }
  1383. }
  1384. while ( TotalRead < dwBufferTotal );
  1385. //
  1386. // Note: On slow connections, it is possible to receive a 100-Continue status after
  1387. // receiving the headers. If that happens, then we want to skip the response and do
  1388. // the WinHttpReceiveResponse again to get the final response/status.
  1389. //
  1390. for (int i=0; i<2; i++)
  1391. {
  1392. if (!WinHttpReceiveResponse(hRequest,0))
  1393. {
  1394. DWORD dwError = GetLastError();
  1395. //
  1396. // Note that 401 will be a case for RESEND.
  1397. // We don't need to set credentials explicitly because our autologon policy
  1398. // is set to LOW and winhttp will automatically grab the NTLM credentials
  1399. // for us
  1400. //
  1401. if (dwError == ERROR_WINHTTP_RESEND_REQUEST)
  1402. {
  1403. Log( LOG_INFO, "WinHttpReceiveResponse failed with ERROR_RESEND_REQUEST" );
  1404. // here we go: do the main loop again and resend
  1405. fDoResend = TRUE;
  1406. break;
  1407. }
  1408. else
  1409. {
  1410. Log( LOG_ERROR, "WinHttpReceiveResponse failed, error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1411. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1412. }
  1413. }
  1414. //
  1415. // Get the status code from the response and decide what to do next
  1416. //
  1417. DWORD dwStatus = GetStatusCode(hRequest);
  1418. if (dwStatus != HTTP_STATUS_CONTINUE)
  1419. {
  1420. // don't do the Receive one more time
  1421. break;
  1422. }
  1423. }
  1424. } while (fDoResend);
  1425. }
  1426. else
  1427. {
  1428. //
  1429. // BY REF case
  1430. //
  1431. Log(LOG_INFO, "Making HTTP request with Notification URL for BYREF case");
  1432. BOOL fRepeat;
  1433. do
  1434. {
  1435. fRepeat = FALSE;
  1436. if ( !WinHttpSendRequest( hRequest,
  1437. NULL,
  1438. 0,
  1439. NULL,
  1440. 0,
  1441. 0,
  1442. 0) )
  1443. {
  1444. Log( LOG_ERROR, "WinHttpSendRequest failed, error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1445. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0,0x7 );
  1446. }
  1447. if (!WinHttpReceiveResponse(hRequest, 0) )
  1448. {
  1449. DWORD dwError = GetLastError();
  1450. //
  1451. // Note that 401 will be a case for RESEND.
  1452. // We don't need to set credentials explicitly because our autologon policy
  1453. // is set to LOW and winhttp will automatically grab the NTLM credentials
  1454. // for us
  1455. //
  1456. if (dwError == ERROR_WINHTTP_RESEND_REQUEST)
  1457. {
  1458. Log( LOG_INFO, "WinHttpReceiveResponse failed with ERROR_RESEND_REQUEST" );
  1459. // repeat the loop
  1460. fRepeat = TRUE;
  1461. }
  1462. else
  1463. {
  1464. Log( LOG_ERROR, "WinHttpReceiveResponse failed, error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1465. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1466. }
  1467. }
  1468. } while (fRepeat);
  1469. }
  1470. //
  1471. // Check for a BITS-Static-Response-URL. If a static response is given,
  1472. // remove the response file and format URL
  1473. //
  1474. bool HasStaticResponse = TestResponseHeader( hRequest, HTTP_STRING( "BITS-Static-Response-URL" ) );
  1475. if ( HasStaticResponse )
  1476. {
  1477. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1478. {
  1479. CloseHandle( hResponseFile );
  1480. hResponseFile = INVALID_HANDLE_VALUE;
  1481. BITSDeleteFile( m_ResponseFile );
  1482. }
  1483. }
  1484. //
  1485. // drain the pipe.
  1486. //
  1487. Log( LOG_INFO, "Processing backend response" );
  1488. DWORD dwStatus = GetStatusCode(hRequest);
  1489. DWORD BytesRead;
  1490. DWORD BytesWritten;
  1491. do
  1492. {
  1493. if (!WinHttpReadData( hRequest,
  1494. m_NotifyBuffer,
  1495. sizeof( m_NotifyBuffer ),
  1496. &BytesRead ))
  1497. {
  1498. Log( LOG_ERROR, "InternetReadFile failed, error %x", HRESULT_FROM_WIN32(GetLastError()) );
  1499. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1500. }
  1501. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1502. {
  1503. if ( !WriteFile(
  1504. hResponseFile,
  1505. m_NotifyBuffer,
  1506. BytesRead,
  1507. &BytesWritten,
  1508. NULL ) )
  1509. {
  1510. Log( LOG_ERROR, "WriteFile failed, error %x",
  1511. HRESULT_FROM_WIN32( GetLastError() ) );
  1512. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1513. }
  1514. }
  1515. }
  1516. while ( BytesRead > 0 );
  1517. //
  1518. // Retrieve or compute the reply URL( the default is to use self-relative form).
  1519. //
  1520. StringHandle ReplyURL;
  1521. if ( HasStaticResponse )
  1522. {
  1523. ReplyURL = GetResponseHeader( hRequest, HTTP_STRING( "BITS-Static-Response-URL" ) );
  1524. }
  1525. else
  1526. {
  1527. if ( INVALID_FILE_ATTRIBUTES != GetFileAttributes( m_ResponseFile ) )
  1528. {
  1529. //
  1530. // Build the relative reply URL
  1531. //
  1532. DWORD URLDepth = m_URLDepth;
  1533. if ( URLDepth ) // The last part is automatically stripped with
  1534. URLDepth--; // relative URLs
  1535. while( URLDepth-- )
  1536. {
  1537. ReplyURL += "..\\";
  1538. }
  1539. ReplyURL += m_DirectoryConfig->m_ConnectionsDir;
  1540. ReplyURL += "\\";
  1541. ReplyURL += REPLIES_DIR_NAME;
  1542. ReplyURL += "\\";
  1543. ReplyURL += m_SessionIdString;
  1544. ReplyURL += "\\";
  1545. ReplyURL += RESPONSE_FILE_NAME;
  1546. }
  1547. }
  1548. if ( TestResponseHeader( hRequest, HTTP_STRING( "BITS-Copy-File-To-Destination" ) ) )
  1549. {
  1550. BITSRenameFile( m_RequestFile,
  1551. m_DestinationFile,
  1552. m_DirectoryConfig->m_AllowOverwrites );
  1553. }
  1554. WinHttpCloseHandle( hRequest );
  1555. WinHttpCloseHandle( hConnect );
  1556. WinHttpCloseHandle( hInternet );
  1557. hRequest = hInternet = hConnect = NULL;
  1558. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1559. CloseHandle( hResponseFile );
  1560. hResponseFile = INVALID_HANDLE_VALUE;
  1561. if ( ReplyURL.Size() > INTERNET_MAX_URL_LENGTH )
  1562. {
  1563. Log( LOG_ERROR, "The reply URL is too long." );
  1564. throw ComError( E_INVALIDARG );
  1565. }
  1566. //
  1567. // Cache the notification response if the error code is
  1568. // 200 or 403
  1569. //
  1570. if ( 200 == dwStatus ||
  1571. 403 == dwStatus )
  1572. {
  1573. m_StateFileStruct->HttpCode = dwStatus;
  1574. if ( ReplyURL.Size() )
  1575. {
  1576. StringCchCopy( m_StateFileStruct->ReplyURL, INTERNET_MAX_URL_LENGTH+1,
  1577. (const CHAR*)ReplyURL );
  1578. m_StateFileStruct->ReplyURLReturned = TRUE;
  1579. }
  1580. m_StateFileStruct->NotifyCached = TRUE;
  1581. }
  1582. #if 0
  1583. // test caching of reply values
  1584. throw ComError( E_FAIL );
  1585. #endif
  1586. if ( ReplyURL.Size() )
  1587. {
  1588. Log( LOG_INFO, "The backend supplied a response url, send client response including URL" );
  1589. SendResponseAfterNotification(
  1590. dwStatus,
  1591. CacheFileSize,
  1592. (const char*)ReplyURL );
  1593. }
  1594. else
  1595. {
  1596. Log( LOG_INFO, "The backend didn't supply a response URL, sending simple client response" );
  1597. SendResponseAfterNotification(
  1598. dwStatus,
  1599. CacheFileSize,
  1600. NULL );
  1601. }
  1602. }
  1603. catch( const ComError & )
  1604. {
  1605. // cleanup
  1606. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1607. {
  1608. CloseHandle( hResponseFile );
  1609. hResponseFile = INVALID_HANDLE_VALUE;
  1610. }
  1611. DeleteFile( m_ResponseFile );
  1612. if ( hRequest )
  1613. WinHttpCloseHandle( hRequest );
  1614. if ( hConnect )
  1615. WinHttpCloseHandle( hConnect );
  1616. if ( hInternet )
  1617. WinHttpCloseHandle( hInternet );
  1618. throw;
  1619. }
  1620. }
  1621. bool
  1622. ServerRequest::TestResponseHeader( HINTERNET hRequest,
  1623. const WCHAR *Header )
  1624. {
  1625. // test for a header in the notification response. If the header is
  1626. // found return true, false if not. Throw an exception on an error.
  1627. SIZE_T HeaderSize = wcslen(Header) + 2;
  1628. WorkStringBufferW WorkStringBufferData( HeaderSize );
  1629. WCHAR *HeaderDup = (WCHAR *)WorkStringBufferData.GetBuffer();
  1630. memcpy( HeaderDup, Header, ( HeaderSize - 1 ) * sizeof( WCHAR ) );
  1631. DWORD BufferLength = (DWORD)HeaderSize;
  1632. BOOL Result = WinHttpQueryHeaders( hRequest,
  1633. WINHTTP_QUERY_CUSTOM,
  1634. Header,
  1635. HeaderDup,
  1636. &BufferLength,
  1637. NULL );
  1638. if ( Result )
  1639. return true;
  1640. DWORD dwLastError = GetLastError();
  1641. if ( ERROR_INSUFFICIENT_BUFFER == dwLastError )
  1642. return true;
  1643. if ( ERROR_WINHTTP_HEADER_NOT_FOUND == dwLastError )
  1644. return false;
  1645. Log( LOG_ERROR, "Unable to test response header %s, error %x",
  1646. (const char*) StringHandle( Header ), HRESULT_FROM_WIN32( GetLastError() ) );
  1647. throw ServerException( HRESULT_FROM_WIN32( dwLastError ) );
  1648. }
  1649. StringHandle
  1650. ServerRequest::GetResponseHeader( HINTERNET hRequest,
  1651. const WCHAR *Header )
  1652. {
  1653. // Retrieve a header from a notification response. If the header is not
  1654. // found or an other error occures, throw an exception.
  1655. SIZE_T HeaderSize = wcslen( Header );
  1656. DWORD BufferLength = (DWORD)( ( HeaderSize + 1024 ) & ~( 1024 - 1 ) );
  1657. HTTPStackStringHandle RetVal;
  1658. while(1)
  1659. {
  1660. WCHAR *Buffer = RetVal.AllocBuffer( BufferLength );
  1661. memcpy( Buffer, Header, ( HeaderSize + 1 ) * sizeof( WCHAR ) );
  1662. BOOL Result = WinHttpQueryHeaders( hRequest,
  1663. WINHTTP_QUERY_CUSTOM,
  1664. Header,
  1665. Buffer,
  1666. &BufferLength,
  1667. NULL );
  1668. if ( Result )
  1669. {
  1670. RetVal.SetStringSize();
  1671. return StringHandle( RetVal );
  1672. }
  1673. DWORD dwError = GetLastError();
  1674. if ( ERROR_INSUFFICIENT_BUFFER != dwError )
  1675. {
  1676. Log( LOG_ERROR, "Unable to get response header %s, error %x",
  1677. ( const char *) StringHandle( Header ), HRESULT_FROM_WIN32( GetLastError() ) );
  1678. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  1679. }
  1680. RetVal = HTTPStackStringHandle();
  1681. if ( BufferLength > BITS_MAX_HEADER_SIZE )
  1682. {
  1683. Log( LOG_ERROR, "The returned header is larger then the maximum size" );
  1684. throw ServerException( E_INVALIDARG );
  1685. }
  1686. }
  1687. }
  1688. void
  1689. ServerRequest::VerifySessionExists()
  1690. {
  1691. WIN32_FILE_ATTRIBUTE_DATA FileInformation;
  1692. if ( !GetFileAttributesEx(
  1693. (const char*)m_RequestDirectory,
  1694. GetFileExInfoStandard,
  1695. (LPVOID)&FileInformation ) )
  1696. {
  1697. DWORD dwError = GetLastError();
  1698. Log( LOG_ERROR, "Error validation on session directory, error %x",
  1699. HRESULT_FROM_WIN32( GetLastError() ) );
  1700. if ( ERROR_PATH_NOT_FOUND == dwError ||
  1701. ERROR_FILE_NOT_FOUND == dwError )
  1702. {
  1703. Log( LOG_ERROR, "Session directory is missing" );
  1704. throw ServerException( BG_E_SESSION_NOT_FOUND );
  1705. }
  1706. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  1707. }
  1708. if ( !( FileInformation.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  1709. {
  1710. Log( LOG_ERROR, "Session directory is missing" );
  1711. throw ServerException( BG_E_SESSION_NOT_FOUND );
  1712. }
  1713. }
  1714. void
  1715. ServerRequest::CloseSession()
  1716. {
  1717. // Handles the Close-Session command from the client.
  1718. CrackSessionId();
  1719. GeneratePhysicalPaths();
  1720. VerifySessionExists();
  1721. if ( BITS_NOTIFICATION_TYPE_NONE == m_DirectoryConfig->m_NotificationType )
  1722. {
  1723. BITSRenameFile( m_RequestFile,
  1724. m_DestinationFile,
  1725. m_DirectoryConfig->m_AllowOverwrites );
  1726. }
  1727. else
  1728. {
  1729. BITSDeleteFile( m_RequestFile );
  1730. }
  1731. BITSDeleteFile( m_ResponseFile );
  1732. BITSDeleteFile( m_StateFile );
  1733. RemoveDirectory( m_RequestDirectory );
  1734. RemoveDirectory( m_ResponseDirectory );
  1735. SendResponse(
  1736. "Pragma: no-cache\r\n"
  1737. "BITS-Packet-Type: Ack\r\n"
  1738. "Content-Length: 0\r\n"
  1739. "\r\n" );
  1740. LogSessionClose( m_SessionId );
  1741. }
  1742. void
  1743. ServerRequest::CancelSession()
  1744. {
  1745. // Handles the Cancel-Session command from the client. Deletes
  1746. // all the temporary files, of the current state.
  1747. CrackSessionId();
  1748. GeneratePhysicalPaths();
  1749. VerifySessionExists();
  1750. BITSDeleteFile( m_ResponseFile );
  1751. BITSDeleteFile( m_RequestFile );
  1752. BITSDeleteFile( m_StateFile );
  1753. RemoveDirectory( m_RequestDirectory );
  1754. RemoveDirectory( m_ResponseDirectory );
  1755. SendResponse(
  1756. "Pragma: no-cache\r\n"
  1757. "BITS-Packet-Type: Ack\r\n"
  1758. "Content-Length: 0\r\n"
  1759. "\r\n" );
  1760. LogSessionCancel( m_SessionId );
  1761. }
  1762. void
  1763. ServerRequest::Ping()
  1764. {
  1765. // Handles the Ping command which is essentually just a no-op.
  1766. SendResponse(
  1767. "Pragma: no-cache\r\n"
  1768. "BITS-Packet-Type: Ack\r\n"
  1769. "Content-Length: 0\r\n"
  1770. "\r\n" );
  1771. }
  1772. CHAR *
  1773. ServerRequest::BasePathOf(const CHAR *pPath)
  1774. {
  1775. CHAR *pBasePath;
  1776. if (!pPath)
  1777. {
  1778. return NULL;
  1779. }
  1780. if ( (pBasePath=strrchr(pPath,'/'))
  1781. || (pBasePath=strrchr(pPath,'\\')) )
  1782. {
  1783. pBasePath++;
  1784. }
  1785. else
  1786. {
  1787. pBasePath = (char *)pPath;
  1788. }
  1789. return pBasePath;
  1790. }
  1791. StringHandle
  1792. ServerRequest::GeneratePathInDestinationDir(LPCSTR szOriginalPath)
  1793. {
  1794. StringHandle NewPath;
  1795. StringHandle TempFileGuid;
  1796. CHAR *pFilePart = NULL;
  1797. GUID guidTempFile;
  1798. if ( !szOriginalPath )
  1799. {
  1800. Log( LOG_ERROR, "Unexpected NULL path was detected" );
  1801. throw ServerException( E_INVALIDARG );
  1802. }
  1803. pFilePart = BasePathOf(szOriginalPath);
  1804. //
  1805. // This will create a file name in the form
  1806. // <destinationdir>\bitssrv_<guid>_<filename>
  1807. // We add the GUID to avoid colision with other threads
  1808. // Note that we won't be using the session GUID to avoid disclosuring the session id.
  1809. // Instead, we will be using a new and random guid.
  1810. //
  1811. guidTempFile = BITSCreateGuid();
  1812. TempFileGuid = BITSStringFromGuid( guidTempFile );
  1813. NewPath = m_DestinationDirectory +
  1814. StringHandle("bitssrv") +
  1815. StringHandle("_") +
  1816. TempFileGuid +
  1817. StringHandle("_") +
  1818. StringHandle(pFilePart);
  1819. return NewPath;
  1820. }
  1821. void
  1822. ServerRequest::GeneratePhysicalPaths()
  1823. {
  1824. const CHAR *PathTranslated = m_ExtensionControlBlock->lpszPathTranslated;
  1825. {
  1826. StringHandle DestinationPath;
  1827. CHAR *FilePart = NULL;
  1828. DWORD BufferLength = MAX_PATH;
  1829. while( 1 )
  1830. {
  1831. CHAR *PathBuffer = DestinationPath.AllocBuffer( BufferLength );
  1832. DWORD Result =
  1833. GetFullPathName(
  1834. m_ExtensionControlBlock->lpszPathTranslated,
  1835. BufferLength,
  1836. PathBuffer,
  1837. &FilePart );
  1838. if ( Result > BufferLength )
  1839. {
  1840. BufferLength = Result;
  1841. continue;
  1842. }
  1843. if ( !Result )
  1844. {
  1845. Log( LOG_ERROR, "Unable to get the full path name for %s, error 0x%8.8X",
  1846. m_ExtensionControlBlock->lpszPathTranslated, HRESULT_FROM_WIN32( GetLastError() ) );
  1847. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1848. }
  1849. if ( !FilePart )
  1850. {
  1851. Log( LOG_ERROR, "Uploading to directories are not supported" );
  1852. throw ServerException( E_INVALIDARG );
  1853. }
  1854. m_DestinationFile = PathBuffer;
  1855. *FilePart = '\0';
  1856. m_DestinationDirectory = PathBuffer;
  1857. break;
  1858. }
  1859. }
  1860. // perform some basic tests on the file name
  1861. DWORD Attributes =
  1862. GetFileAttributes( m_DestinationFile );
  1863. if ( (DWORD)INVALID_FILE_ATTRIBUTES == Attributes )
  1864. {
  1865. if ( ( GetLastError() != ERROR_FILE_NOT_FOUND ) &&
  1866. ( GetLastError() != ERROR_ACCESS_DENIED ) )
  1867. {
  1868. Log( LOG_ERROR, "Unable to get the file attributes for %s, error 0x%8.8X",
  1869. m_ExtensionControlBlock->lpszPathTranslated, HRESULT_FROM_WIN32( GetLastError() ) );
  1870. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1871. }
  1872. }
  1873. else
  1874. {
  1875. // file exists, check if its a directory
  1876. if ( FILE_ATTRIBUTE_DIRECTORY & Attributes )
  1877. {
  1878. Log( LOG_ERROR, "Uploading to directories are not supported" );
  1879. throw ServerException( E_INVALIDARG );
  1880. }
  1881. // deny access if the ability to overwrite existing files is turned off
  1882. if ( !m_DirectoryConfig->m_AllowOverwrites &&
  1883. ( BITS_NOTIFICATION_TYPE_NONE == m_DirectoryConfig->m_NotificationType ) )
  1884. {
  1885. Log( LOG_ERROR, "The destination exists, but the ability to allow overwrites is turned off" );
  1886. throw ServerException( HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) );
  1887. }
  1888. }
  1889. // validate that the physical path is below the virtual directory root
  1890. {
  1891. SIZE_T VDirPathSize = m_DirectoryConfig->m_PhysicalPath.Size();
  1892. if ( _strnicmp( m_DirectoryConfig->m_PhysicalPath, m_DestinationDirectory, VDirPathSize ) != 0 )
  1893. {
  1894. Log( LOG_ERROR, "Path is not below the virtual directory root, error" );
  1895. throw ServerException( E_INVALIDARG );
  1896. }
  1897. }
  1898. // validate that the physical path does not end with a slash or colon
  1899. {
  1900. SIZE_T PathSize = strlen( PathTranslated );
  1901. if ( PathSize )
  1902. {
  1903. if ( '\\' == PathTranslated[ PathSize - 1 ] ||
  1904. '/' == PathTranslated[ PathSize - 1 ] )
  1905. {
  1906. Log( LOG_ERROR, "Path can not end with a slash" );
  1907. throw ServerException( E_INVALIDARG );
  1908. }
  1909. if ( ':' == PathTranslated[ PathSize - 1 ] )
  1910. {
  1911. Log( LOG_ERROR, "Path may not end with a colon" );
  1912. throw ServerException( E_INVALIDARG );
  1913. }
  1914. }
  1915. }
  1916. m_RequestDirectory = m_DirectoryConfig->m_RequestsDir + StringHandle("\\") +
  1917. m_SessionIdString;
  1918. m_RequestFile = m_RequestDirectory + StringHandle("\\") +
  1919. StringHandle( REQUEST_FILE_NAME );
  1920. m_StateFile = m_RequestDirectory + StringHandle("\\") +
  1921. StringHandle( STATE_FILE_NAME );
  1922. m_ResponseDirectory = m_DirectoryConfig->m_RepliesDir + StringHandle("\\") +
  1923. m_SessionIdString;
  1924. m_ResponseFile = m_ResponseDirectory + StringHandle("\\") +
  1925. StringHandle(RESPONSE_FILE_NAME);
  1926. // validate that the physical path is not inside the cache directory
  1927. {
  1928. SIZE_T SessionDirSize = m_DirectoryConfig->m_SessionDir.Size();
  1929. if ( _strnicmp( (const char*)m_DirectoryConfig->m_SessionDir,
  1930. (const char*)m_DestinationDirectory, SessionDirSize ) == 0 )
  1931. {
  1932. Log( LOG_ERROR, "Path can not be inside the cache directory" );
  1933. throw ServerException( HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) );
  1934. }
  1935. }
  1936. }
  1937. void
  1938. ServerRequest::CheckFilesystemAccess()
  1939. {
  1940. if ( !m_ImpersonationToken )
  1941. return;
  1942. PSECURITY_DESCRIPTOR pSd = NULL;
  1943. DWORD Result =
  1944. GetNamedSecurityInfo(
  1945. (char*)(const char*)m_DestinationDirectory,
  1946. SE_FILE_OBJECT,
  1947. DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
  1948. NULL,
  1949. NULL,
  1950. NULL,
  1951. NULL,
  1952. &pSd );
  1953. // If we can't read the SD, assume that everything is ok
  1954. if ( ERROR_ACCESS_DENIED == Result )
  1955. {
  1956. Log( LOG_WARNING, "Assuming access is granted, let later operations fail" );
  1957. return;
  1958. }
  1959. GENERIC_MAPPING FileMapping =
  1960. {
  1961. FILE_GENERIC_READ,
  1962. FILE_GENERIC_WRITE,
  1963. FILE_GENERIC_EXECUTE,
  1964. FILE_ALL_ACCESS
  1965. };
  1966. BYTE PrivilageBuffer[ sizeof( PRIVILEGE_SET ) + sizeof( LUID_AND_ATTRIBUTES ) ];
  1967. DWORD PrivilegeSetLength = sizeof( PrivilageBuffer ); // size of privileges buffer
  1968. DWORD GrantedAccess = 0; // granted access rights
  1969. BOOL AccessStatus = FALSE; // result of access check
  1970. if ( !AccessCheck(
  1971. pSd, // SD
  1972. m_ImpersonationToken, // handle to client access token
  1973. FILE_WRITE_DATA, // requested access rights
  1974. &FileMapping, // mapping
  1975. (PPRIVILEGE_SET)PrivilageBuffer, // privileges
  1976. &PrivilegeSetLength, // size of privileges buffer
  1977. &GrantedAccess, // granted access rights
  1978. &AccessStatus // result of access check
  1979. ) )
  1980. {
  1981. HRESULT Error = HRESULT_FROM_WIN32( GetLastError() );
  1982. Log( LOG_ERROR, "Unable to check access, error 0x%8.8X", Error );
  1983. LocalFree( pSd );
  1984. throw ComError( Error );
  1985. }
  1986. LocalFree( pSd );
  1987. if ( !AccessStatus )
  1988. {
  1989. Log( LOG_ERROR, "Denying access since the caller does not have create file rights" );
  1990. throw ServerException( E_ACCESSDENIED, 403 );
  1991. }
  1992. }
  1993. HANDLE
  1994. ServerRequest::CreateFileWithDestinationAcls(const CHAR *szOriginalFile, DWORD fOnlyCreateNew, DWORD dwAttributes)
  1995. {
  1996. CHAR *pFile = const_cast<char *>(szOriginalFile);
  1997. DWORD dwDispositionFlags = OPEN_EXISTING;
  1998. BOOL fRetry = FALSE;
  1999. HANDLE hFile = INVALID_HANDLE_VALUE;
  2000. StringHandle TempPath;
  2001. if (fOnlyCreateNew)
  2002. {
  2003. TempPath = GeneratePathInDestinationDir(szOriginalFile);
  2004. pFile = const_cast<char *>(static_cast<const char *>(TempPath));
  2005. dwDispositionFlags = CREATE_ALWAYS;
  2006. }
  2007. //
  2008. // Open the file.
  2009. // If the file exists, we will leave it alone an assume the Acls are correct
  2010. // Otherwise we will create the file first in m_DestinationDir so it has the VDIR Acls,
  2011. // and then move it to the proper directory.
  2012. //
  2013. do
  2014. {
  2015. fRetry = FALSE;
  2016. hFile =
  2017. CreateFile(
  2018. pFile,
  2019. GENERIC_READ | GENERIC_WRITE,
  2020. 0,
  2021. NULL,
  2022. dwDispositionFlags,
  2023. dwAttributes,
  2024. NULL );
  2025. if (hFile == INVALID_HANDLE_VALUE)
  2026. {
  2027. DWORD dwError = GetLastError();
  2028. //
  2029. // if we are creating the file, we want to create it in the DestinationDir
  2030. // so it has the right ACLs, and then move it to the right directory.
  2031. //
  2032. if (!fOnlyCreateNew && dwError == ERROR_FILE_NOT_FOUND)
  2033. {
  2034. TempPath = GeneratePathInDestinationDir(szOriginalFile);
  2035. pFile = const_cast<char *>(static_cast<const char *>(TempPath));
  2036. dwDispositionFlags = CREATE_ALWAYS;
  2037. fRetry = TRUE;
  2038. Log( LOG_INFO, "First time creating file. Will create file first at %s", pFile);
  2039. continue;
  2040. }
  2041. else
  2042. {
  2043. Log( LOG_ERROR, "Unable to open file %s, error 0x%8.8X", pFile, HRESULT_FROM_WIN32( dwError ));
  2044. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  2045. }
  2046. }
  2047. } while (fRetry);
  2048. //
  2049. // Ok, we are done opening the file, now see if we need to move the file to
  2050. // the right location.
  2051. // Unfortunately, because we want to open the file with no sharing allowed, we need to close
  2052. // the handle and reopen it.
  2053. //
  2054. if (dwDispositionFlags == CREATE_ALWAYS)
  2055. {
  2056. CloseHandle(hFile);
  2057. hFile = INVALID_HANDLE_VALUE;
  2058. if (!MoveFile(pFile, szOriginalFile))
  2059. {
  2060. DWORD dwError = GetLastError();
  2061. DeleteFile(pFile);
  2062. Log( LOG_ERROR, "Unable to move file from %s to %s, error 0x%8.8X",
  2063. pFile, szOriginalFile, HRESULT_FROM_WIN32( dwError ));
  2064. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  2065. }
  2066. hFile =
  2067. CreateFile(
  2068. szOriginalFile,
  2069. GENERIC_READ | GENERIC_WRITE,
  2070. 0,
  2071. NULL,
  2072. OPEN_EXISTING,
  2073. dwAttributes,
  2074. NULL );
  2075. if (hFile == INVALID_HANDLE_VALUE)
  2076. {
  2077. DWORD dwError = GetLastError();
  2078. Log( LOG_ERROR, "Unable to open file %s, error 0x%8.8X", szOriginalFile, HRESULT_FROM_WIN32( dwError ));
  2079. throw ComError( HRESULT_FROM_WIN32( dwError ) );
  2080. }
  2081. }
  2082. return hFile;
  2083. }
  2084. void
  2085. ServerRequest::OpenCacheFile( )
  2086. {
  2087. // Open the cache file.
  2088. try
  2089. {
  2090. m_CacheFile = CreateFileWithDestinationAcls( m_RequestFile, FALSE, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED );
  2091. }
  2092. catch (ComError Error)
  2093. {
  2094. DWORD dwError = Error.m_Hr;
  2095. if (dwError == ERROR_PATH_NOT_FOUND)
  2096. {
  2097. throw ServerException( BG_E_SESSION_NOT_FOUND );
  2098. }
  2099. throw ServerException( Error.m_Hr );
  2100. }
  2101. }
  2102. void
  2103. ServerRequest::ReopenCacheFileAsSync()
  2104. {
  2105. // reopen the cache file as async so that it can be spooled synchronously over
  2106. // to the backend.
  2107. CloseCacheFile();
  2108. m_CacheFile =
  2109. CreateFile(
  2110. m_RequestFile,
  2111. GENERIC_READ | GENERIC_WRITE,
  2112. 0,
  2113. NULL,
  2114. OPEN_EXISTING,
  2115. FILE_ATTRIBUTE_NORMAL,
  2116. NULL );
  2117. if ( INVALID_HANDLE_VALUE == m_CacheFile )
  2118. {
  2119. Log( LOG_ERROR, "Unable to reopen cache file %s, error 0x%8.8X",
  2120. (const char*)m_RequestFile,
  2121. HRESULT_FROM_WIN32( GetLastError() ) );
  2122. if (GetLastError() == ERROR_PATH_NOT_FOUND)
  2123. {
  2124. throw ServerException( BG_E_SESSION_NOT_FOUND );
  2125. }
  2126. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  2127. }
  2128. }
  2129. void
  2130. ServerRequest::CloseCacheFile()
  2131. {
  2132. // Close the cache file, if it isn't already closed.
  2133. if ( INVALID_HANDLE_VALUE != m_CacheFile )
  2134. {
  2135. if ( CloseHandle( m_CacheFile ) )
  2136. m_CacheFile = INVALID_HANDLE_VALUE;
  2137. }
  2138. }
  2139. void
  2140. ServerRequest::ForwardComplete(
  2141. LPEXTENSION_CONTROL_BLOCK lpECB,
  2142. PVOID pContext,
  2143. DWORD cbIO,
  2144. DWORD dwError)
  2145. {
  2146. // A do nothing callback for forwarding the request.
  2147. ServerRequest *This = (ServerRequest*)pContext;
  2148. This->Release( );
  2149. }
  2150. void
  2151. ServerRequest::ForwardToNextISAPI()
  2152. {
  2153. // IIS6 has changed behavior where the limit on * entries are ignored.
  2154. // To work around this problem, it is necessary to send the request back
  2155. // to IIS.
  2156. BOOL Result;
  2157. Result =
  2158. (*m_ExtensionControlBlock->ServerSupportFunction)(
  2159. m_ExtensionControlBlock->ConnID,
  2160. HSE_REQ_IO_COMPLETION,
  2161. (LPVOID)ForwardComplete,
  2162. 0,
  2163. (LPDWORD)this );
  2164. if ( !Result )
  2165. {
  2166. Log( LOG_ERROR, "Unable to set callback to ForwardComplete, error %x",
  2167. HRESULT_FROM_WIN32( GetLastError() ) );
  2168. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  2169. }
  2170. HSE_EXEC_URL_INFO ExecInfo;
  2171. memset( &ExecInfo, 0, sizeof( ExecInfo ) );
  2172. #define HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR 0x04
  2173. ExecInfo.dwExecUrlFlags = HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR;
  2174. ScheduleAsyncOperation(
  2175. HSE_REQ_EXEC_URL,
  2176. (LPVOID)&ExecInfo,
  2177. NULL,
  2178. NULL );
  2179. return;
  2180. }
  2181. void
  2182. ServerRequest::GetConfig()
  2183. {
  2184. // Looks up the configuration to use for this request.
  2185. StringHandle InstanceMetaPath = GetServerVariable( "INSTANCE_META_PATH" );
  2186. StringHandle URL = GetServerVariable( "URL" );
  2187. m_DirectoryConfig = g_ConfigMan->GetConfig( InstanceMetaPath, URL, &m_URLDepth );
  2188. }
  2189. void
  2190. ServerRequest::DispatchRequest()
  2191. {
  2192. //
  2193. // The main do it function, parse what kind of request the client is sending and
  2194. // dispatch it to the appropiate handler routines.
  2195. //
  2196. // This critical section is needed because IIS callbacks can happen on any time.
  2197. // The lock is needed to prevent a callback from happening while the dispatch
  2198. // routine is still running.
  2199. CriticalSectionLock CSLock( &m_cs );
  2200. try
  2201. {
  2202. if ( _stricmp( m_ExtensionControlBlock->lpszMethod, BITS_COMMAND_VERBA ) != 0 )
  2203. {
  2204. Log( LOG_CALLBEGIN, "Connection %p, Packet-Type: %s, Method: %s, Path %s",
  2205. m_ExtensionControlBlock->ConnID,
  2206. (const char*)"UNKNOWN",
  2207. m_ExtensionControlBlock->lpszMethod,
  2208. m_ExtensionControlBlock->lpszPathTranslated );
  2209. ForwardToNextISAPI();
  2210. return;
  2211. }
  2212. m_PacketType = GetServerVariable( "HTTP_BITS-PACKET-TYPE" );
  2213. Log( LOG_CALLBEGIN, "Connection %p, Packet-Type: %s, Method: %s, Path %s",
  2214. m_ExtensionControlBlock->ConnID,
  2215. (const char*)m_PacketType,
  2216. m_ExtensionControlBlock->lpszMethod,
  2217. m_ExtensionControlBlock->lpszPathTranslated );
  2218. if (! m_ExtensionControlBlock->ServerSupportFunction(
  2219. m_ExtensionControlBlock->ConnID,
  2220. HSE_REQ_GET_IMPERSONATION_TOKEN,
  2221. &m_ImpersonationToken,
  2222. NULL,
  2223. NULL ) )
  2224. {
  2225. Log( LOG_ERROR, "Unable to get the impersonation token" );
  2226. throw ServerException( HRESULT_FROM_WIN32( E_INVALIDARG ) );
  2227. }
  2228. GetConfig();
  2229. if ( !m_DirectoryConfig->m_UploadEnabled )
  2230. {
  2231. Log( LOG_ERROR, "BITS uploads are not enabled" );
  2232. throw ServerException( E_ACCESSDENIED, 501 );
  2233. }
  2234. if ( m_DirectoryConfig->m_ExecutePermissions & ( MD_ACCESS_EXECUTE | MD_ACCESS_SCRIPT ) )
  2235. {
  2236. Log( LOG_ERROR, "BITS uploads are disable because execute or script access is enabled" );
  2237. LogExecuteEnabled();
  2238. throw ServerException( BG_E_SERVER_EXECUTE_ENABLE, 403 );
  2239. }
  2240. StringHandle ContentLength = GetServerVariable( "HTTP_Content-Length" );
  2241. if ( 1 != sscanf( (const char*)ContentLength, "%I64u", &m_ContentLength ) )
  2242. {
  2243. Log( LOG_ERROR, "The content length is broken" );
  2244. throw ServerException( E_INVALIDARG );
  2245. }
  2246. if ( m_ContentLength < m_ExtensionControlBlock->cbAvailable )
  2247. throw ServerException( E_INVALIDARG );
  2248. m_BytesToDrain = m_ContentLength - m_ExtensionControlBlock->cbAvailable;
  2249. //
  2250. // Dispatch to the correct method
  2251. //
  2252. // Create-session
  2253. // fragment
  2254. // Get-Reply-Url
  2255. // Close-Session
  2256. // Cancel-Session
  2257. // Ping ( Is server alive )
  2258. // keep this list ordered by frequency
  2259. if ( _stricmp( m_PacketType, PACKET_TYPE_FRAGMENT ) == 0 )
  2260. AddFragment();
  2261. else if ( _stricmp( m_PacketType, PACKET_TYPE_PING ) == 0 )
  2262. Ping();
  2263. else if ( _stricmp( m_PacketType, PACKET_TYPE_CREATE_SESSION ) == 0 )
  2264. CreateSession();
  2265. else if ( _stricmp( m_PacketType, PACKET_TYPE_CLOSE_SESSION ) == 0 )
  2266. CloseSession();
  2267. else if ( _stricmp( m_PacketType, PACKET_TYPE_CANCEL_SESSION ) == 0 )
  2268. CancelSession();
  2269. else
  2270. {
  2271. Log( LOG_ERROR, "Received unknown BITS packet type %s",
  2272. (const char*)m_PacketType );
  2273. throw ServerException( E_INVALIDARG );
  2274. }
  2275. }
  2276. catch( ServerException Exception )
  2277. {
  2278. SendResponse( Exception );
  2279. }
  2280. catch( ComError Exception )
  2281. {
  2282. SendResponse( Exception );
  2283. }
  2284. }
  2285. //
  2286. // IIS Logger functions
  2287. //
  2288. void IISLogger::LogString( const char *String, int Size )
  2289. {
  2290. DWORD StringSize = Size + 1;
  2291. (*m_ExtensionControlBlock->ServerSupportFunction)
  2292. (
  2293. m_ExtensionControlBlock->ConnID,
  2294. HSE_APPEND_LOG_PARAMETER,
  2295. (LPVOID)String,
  2296. &StringSize,
  2297. NULL
  2298. );
  2299. }
  2300. void IISLogger::LogError( ServerException Error )
  2301. {
  2302. char OutputStr[ 255 ];
  2303. StringCbPrintfA(
  2304. OutputStr,
  2305. sizeof( OutputStr ),
  2306. "(bits_error:,%u,0x%8.8X)",
  2307. Error.GetHttpCode(),
  2308. Error.GetCode() );
  2309. LogString( OutputStr, strlen( OutputStr ) );
  2310. }
  2311. void IISLogger::LogError( const GUID & SessionID, ServerException Error )
  2312. {
  2313. WCHAR GuidStr[ 50 ];
  2314. char OutputStr[ 255 ];
  2315. StringFromGUID2( SessionID, GuidStr, 50 );
  2316. StringCchPrintfA(
  2317. OutputStr,
  2318. sizeof( OutputStr ),
  2319. "(bits_error:%S,%u,0x%8.8X)",
  2320. GuidStr,
  2321. Error.GetHttpCode(),
  2322. Error.GetCode() );
  2323. LogString( OutputStr, strlen( OutputStr ) );
  2324. }
  2325. void IISLogger::LogNewSession( const GUID & SessionID )
  2326. {
  2327. WCHAR GuidStr[ 50 ];
  2328. char OutputStr[ 255 ];
  2329. StringFromGUID2( SessionID, GuidStr, 50 );
  2330. StringCbPrintfA(
  2331. OutputStr,
  2332. sizeof( OutputStr ),
  2333. "(bits_new_session:%S)",
  2334. GuidStr );
  2335. LogString( OutputStr, strlen( OutputStr ) );
  2336. }
  2337. void IISLogger::LogUploadComplete( const GUID & SessionID, UINT64 FileSize )
  2338. {
  2339. WCHAR GuidStr[ 50 ];
  2340. char OutputStr[ 255 ];
  2341. StringFromGUID2( SessionID, GuidStr, 50 );
  2342. StringCbPrintfA(
  2343. OutputStr,
  2344. sizeof( OutputStr ),
  2345. "(bits_upload_complete:%S,%I64u)",
  2346. GuidStr,
  2347. FileSize );
  2348. LogString( OutputStr, strlen( OutputStr ) );
  2349. }
  2350. void IISLogger::LogSessionClose( const GUID & SessionID )
  2351. {
  2352. WCHAR GuidStr[ 50 ];
  2353. char OutputStr[ 255 ];
  2354. StringFromGUID2( SessionID, GuidStr, 50 );
  2355. StringCbPrintfA(
  2356. OutputStr,
  2357. sizeof( OutputStr ),
  2358. "(bits_close_session:%S)",
  2359. GuidStr );
  2360. LogString( OutputStr, strlen( OutputStr ) );
  2361. }
  2362. void IISLogger::LogSessionCancel( const GUID & SessionID )
  2363. {
  2364. WCHAR GuidStr[ 50 ];
  2365. char OutputStr[ 255 ];
  2366. StringFromGUID2( SessionID, GuidStr, 50 );
  2367. StringCbPrintfA(
  2368. OutputStr,
  2369. sizeof( OutputStr ),
  2370. "(bits_cancel_session:%S)",
  2371. GuidStr );
  2372. LogString( OutputStr, strlen( OutputStr ) );
  2373. }
  2374. void IISLogger::LogExecuteEnabled()
  2375. {
  2376. char OutputStr[ 255 ];
  2377. StringCchPrintfA(
  2378. OutputStr,
  2379. sizeof( OutputStr ),
  2380. "(bits_execute_enabled)" );
  2381. LogString( OutputStr, strlen( OutputStr ) );
  2382. }
  2383. ServerRequest *g_LastRequest = NULL;
  2384. //
  2385. // AsyncReader functions
  2386. //
  2387. AsyncReader::AsyncReader(
  2388. ServerRequest *Request,
  2389. UINT64 BytesToDrain,
  2390. UINT64 BytesToWrite,
  2391. UINT64 WriteOffset,
  2392. HANDLE WriteHandle,
  2393. char *PrereadBuffer,
  2394. DWORD PrereadSize ) :
  2395. m_Request( Request ),
  2396. m_BytesToDrain( BytesToDrain ),
  2397. m_BytesToWrite( BytesToWrite ),
  2398. m_WriteOffset( WriteOffset ),
  2399. m_ReadOffset( WriteOffset ),
  2400. m_WriteHandle( WriteHandle ),
  2401. m_BytesToRead( BytesToWrite ),
  2402. m_PrereadBuffer( PrereadBuffer ),
  2403. m_PrereadSize( PrereadSize ),
  2404. m_OperationsPending( 0 ),
  2405. m_ReadBuffer( 0 ),
  2406. m_WriteBuffer( 0 ),
  2407. m_BuffersToWrite( 0 ),
  2408. m_Error( S_OK ),
  2409. m_WritePending( false ),
  2410. m_ReadPending( false ),
  2411. m_TotalBytesRead( 0 ),
  2412. m_ThreadToken( NULL ),
  2413. m_ErrorValid( false )
  2414. {
  2415. #if defined CLEARASYNCBUFFERS
  2416. for ( int i = 0; i < NUMBER_OF_IO_BUFFERS; i++ )
  2417. {
  2418. memset( m_IOBuffers + i, i, sizeof( *m_IOBuffers ) );
  2419. }
  2420. #endif
  2421. if ( !OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &m_ThreadToken ) )
  2422. {
  2423. Log( LOG_ERROR, "Unable to retrieve the current thread token, error %x",
  2424. HRESULT_FROM_WIN32( GetLastError() ) );
  2425. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  2426. }
  2427. if ( m_BytesToDrain && m_PrereadSize )
  2428. {
  2429. Log( LOG_INFO, "Have both a Preread and bytes to drain, deal with it." );
  2430. Log( LOG_INFO, "BytesToDrain: %I64u, PrereadSize: %u", m_BytesToDrain, m_PrereadSize );
  2431. DWORD DrainBytesInPreread = (DWORD)min( m_BytesToDrain, PrereadSize );
  2432. m_PrereadBuffer += DrainBytesInPreread;
  2433. m_PrereadSize -= DrainBytesInPreread;
  2434. m_BytesToDrain -= DrainBytesInPreread;
  2435. Log( LOG_INFO, "Bytes to drain from preread, %u", DrainBytesInPreread );
  2436. }
  2437. ASSERT( !( m_BytesToDrain && m_PrereadSize ) );
  2438. m_BytesToRead = m_BytesToRead + m_BytesToDrain - m_PrereadSize;
  2439. m_ReadOffset = m_ReadOffset - m_BytesToDrain + m_PrereadSize;
  2440. if ( m_BytesToRead )
  2441. {
  2442. // Setup the read completion callback
  2443. BOOL Result =
  2444. (*m_Request->m_ExtensionControlBlock->ServerSupportFunction)(
  2445. m_Request->m_ExtensionControlBlock->ConnID,
  2446. HSE_REQ_IO_COMPLETION,
  2447. (LPVOID)ReadCompleteWraper,
  2448. 0,
  2449. (LPDWORD)this );
  2450. if ( !Result )
  2451. {
  2452. Log( LOG_ERROR, "Unable to set callback to ReadCompleteWraper, error %x",
  2453. HRESULT_FROM_WIN32( GetLastError() ) );
  2454. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  2455. }
  2456. }
  2457. if ( INVALID_HANDLE_VALUE != m_WriteHandle )
  2458. {
  2459. BOOL Result =
  2460. BindIoCompletionCallback(
  2461. m_WriteHandle, // handle to file
  2462. (LPOVERLAPPED_COMPLETION_ROUTINE)WriteCompleteWraper, // callback
  2463. 0 // reserved
  2464. );
  2465. if ( !Result )
  2466. {
  2467. Log( LOG_ERROR, "Unable to set write completion routing, error %x",
  2468. HRESULT_FROM_WIN32( GetLastError() ) );
  2469. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  2470. }
  2471. }
  2472. // Queue the IO to a thread pool work item.
  2473. BOOL bResult =
  2474. QueueUserWorkItem( StartupIOWraper, this, WT_EXECUTEDEFAULT );
  2475. if ( !bResult )
  2476. {
  2477. Log( LOG_ERROR, "QueueUserWorkItem failed, error %x",
  2478. HRESULT_FROM_WIN32( GetLastError() ) );
  2479. throw ServerException( 500, HRESULT_FROM_WIN32( GetLastError() ) );
  2480. }
  2481. m_OperationsPending++;
  2482. Request->m_IsPending = true;
  2483. Request->AddRef();
  2484. }
  2485. AsyncReader::~AsyncReader()
  2486. {
  2487. if ( m_ThreadToken )
  2488. CloseHandle( m_ThreadToken );
  2489. }
  2490. void
  2491. AsyncReader::HandleError( ServerException Error )
  2492. {
  2493. m_ErrorValid = true;
  2494. m_Error = Error;
  2495. if ( m_OperationsPending )
  2496. return; // Continue to wait for operations to exit.
  2497. m_Request->HandleIOError( this, Error, m_TotalBytesRead );
  2498. return;
  2499. }
  2500. void
  2501. AsyncReader::CompleteIO()
  2502. {
  2503. m_Request->CompleteIO( this, m_TotalBytesRead );
  2504. return;
  2505. }
  2506. void
  2507. AsyncReader::StartReadRequest()
  2508. {
  2509. // start a new IIS read request
  2510. DWORD BytesToRead;
  2511. IOBuffer *Buffer = m_IOBuffers + m_ReadBuffer;
  2512. if ( m_BytesToDrain )
  2513. {
  2514. Buffer->m_BufferWriteOffset = 0;
  2515. Buffer->m_BufferUsed = 0;
  2516. BytesToRead = (DWORD)min( m_BytesToDrain, sizeof( Buffer->m_Buffer ) );
  2517. }
  2518. else
  2519. {
  2520. Buffer->m_BufferWriteOffset = m_ReadOffset;
  2521. Buffer->m_BufferUsed = 0;
  2522. BytesToRead = (DWORD)min( m_BytesToRead, sizeof( Buffer->m_Buffer ) );
  2523. }
  2524. Log( LOG_INFO, "Start Async Read, Connection %p, Buffer %u, Offset %I64u, Length %u",
  2525. m_Request->m_ExtensionControlBlock->ConnID,
  2526. m_ReadBuffer,
  2527. m_ReadOffset,
  2528. BytesToRead );
  2529. DWORD Flags = HSE_IO_ASYNC;
  2530. BOOL Result =
  2531. (*m_Request->m_ExtensionControlBlock->ServerSupportFunction)
  2532. (
  2533. m_Request->m_ExtensionControlBlock->ConnID,
  2534. HSE_REQ_ASYNC_READ_CLIENT,
  2535. Buffer->m_Buffer,
  2536. &BytesToRead,
  2537. &Flags
  2538. );
  2539. if ( !Result )
  2540. {
  2541. DWORD Error = GetLastError();
  2542. Log( LOG_ERROR, "HSE_REQ_ASYNC_READ_CLIENT failed, error 0x%8.8", Error );
  2543. throw ServerException( HRESULT_FROM_WIN32( Error ) );
  2544. }
  2545. m_OperationsPending++;
  2546. m_ReadPending = true;
  2547. m_Request->AddRef();
  2548. }
  2549. void
  2550. AsyncReader::StartWriteRequest()
  2551. {
  2552. // Start a new filesystem write request
  2553. OVERLAPPED *OverLapped = (OVERLAPPED*)this;
  2554. memset( OverLapped, 0, sizeof(*OverLapped) );
  2555. LPCVOID WriteBuffer;
  2556. DWORD BytesToWrite;
  2557. if ( m_PrereadSize )
  2558. {
  2559. // IIS preread data is handled seperatly. Drain it first.
  2560. WriteBuffer = m_PrereadBuffer;
  2561. BytesToWrite = m_PrereadSize;
  2562. }
  2563. else
  2564. {
  2565. IOBuffer *Buffer = m_IOBuffers + m_WriteBuffer;
  2566. ASSERT( m_WriteOffset == Buffer->m_BufferWriteOffset );
  2567. WriteBuffer = Buffer->m_Buffer;
  2568. BytesToWrite = Buffer->m_BufferUsed;
  2569. }
  2570. OverLapped->Offset = (DWORD)(m_WriteOffset & 0xFFFFFFFF);
  2571. OverLapped->OffsetHigh = (DWORD)((m_WriteOffset >> 32) & 0xFFFFFFFF);
  2572. Log( LOG_INFO, "Start Async Write, Connection %p, Buffer %u, Offset %I64u, Length %u",
  2573. m_Request->m_ExtensionControlBlock->ConnID,
  2574. m_WriteBuffer,
  2575. m_WriteOffset,
  2576. BytesToWrite );
  2577. BOOL Result =
  2578. WriteFile(
  2579. m_WriteHandle,
  2580. WriteBuffer,
  2581. BytesToWrite,
  2582. NULL,
  2583. OverLapped );
  2584. if ( !Result && GetLastError() != ERROR_IO_PENDING )
  2585. {
  2586. DWORD Error = GetLastError();
  2587. Log( LOG_ERROR, "WriteFileEx failed, error 0x%8.8X", GetLastError() );
  2588. throw ServerException( HRESULT_FROM_WIN32( Error ) );
  2589. }
  2590. m_OperationsPending++;
  2591. m_WritePending = true;
  2592. m_Request->AddRef();
  2593. }
  2594. void
  2595. AsyncReader::StartupIO( )
  2596. {
  2597. // Startup the necessary IO operations based on the
  2598. // buffer states. returns true if the upload operation should continue.
  2599. try
  2600. {
  2601. if ( m_ErrorValid )
  2602. throw ServerException( m_Error );
  2603. bool ScheduledIO = false;
  2604. if ( m_BytesToDrain )
  2605. {
  2606. StartReadRequest();
  2607. ScheduledIO = true;
  2608. }
  2609. else
  2610. {
  2611. if ( !m_BytesToWrite && !m_BytesToDrain )
  2612. return CompleteIO();
  2613. if ( !m_WritePending )
  2614. {
  2615. if ( m_PrereadSize )
  2616. {
  2617. StartWriteRequest();
  2618. ScheduledIO = true;
  2619. }
  2620. else if ( m_BuffersToWrite )
  2621. {
  2622. StartWriteRequest();
  2623. ScheduledIO = true;
  2624. }
  2625. }
  2626. if ( !m_ReadPending && m_BytesToRead && ( NUMBER_OF_IO_BUFFERS - m_BuffersToWrite ) )
  2627. {
  2628. StartReadRequest();
  2629. ScheduledIO = true;
  2630. }
  2631. }
  2632. if ( !ScheduledIO )
  2633. Log( LOG_INFO, "No IO scheduled" );
  2634. }
  2635. catch( ServerException Error )
  2636. {
  2637. HandleError( Error );
  2638. }
  2639. catch( ComError Error )
  2640. {
  2641. HandleError( Error );
  2642. }
  2643. return;
  2644. }
  2645. void
  2646. AsyncReader::WriteComplete( DWORD dwError, DWORD BytesWritten )
  2647. {
  2648. // Called when a write is completed. Determine the next buffer to use and startup the correct IO operations.
  2649. // returns true is more operations are necessary.
  2650. try
  2651. {
  2652. Log( LOG_INFO, "Complete Async Write, Connection %p, Buffer %u, Offset %I64u, Length %u, Error %u",
  2653. m_Request->m_ExtensionControlBlock->ConnID,
  2654. m_WriteBuffer,
  2655. m_WriteOffset,
  2656. BytesWritten,
  2657. dwError );
  2658. if ( m_ErrorValid )
  2659. throw ServerException( m_Error );
  2660. m_WritePending = false;
  2661. if ( dwError )
  2662. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  2663. m_BytesToWrite -= BytesWritten;
  2664. if ( m_PrereadSize )
  2665. {
  2666. m_PrereadSize -= BytesWritten;
  2667. m_PrereadBuffer += BytesWritten;
  2668. m_WriteOffset += BytesWritten;
  2669. }
  2670. else
  2671. {
  2672. IOBuffer *Buffer = m_IOBuffers + m_WriteBuffer;
  2673. ASSERT( BytesWritten == Buffer->m_BufferUsed );
  2674. m_WriteOffset += Buffer->m_BufferUsed;
  2675. m_BuffersToWrite--;
  2676. #if defined CLEARASYNCBUFFERS
  2677. memset( Buffer, m_WriteBuffer, sizeof(*Buffer) );
  2678. #endif
  2679. m_WriteBuffer = (m_WriteBuffer + 1 ) % NUMBER_OF_IO_BUFFERS;
  2680. }
  2681. return StartupIO();
  2682. }
  2683. catch( ServerException Error )
  2684. {
  2685. Log( LOG_ERROR, "Error in write complete" );
  2686. HandleError( Error );
  2687. }
  2688. catch( ComError Error )
  2689. {
  2690. Log( LOG_ERROR, "Error in write complete" );
  2691. HandleError( Error );
  2692. }
  2693. }
  2694. void
  2695. AsyncReader::ReadComplete( DWORD dwError, DWORD BytesRead )
  2696. {
  2697. // Called when a read operation is complete. determines if more operations should start or to
  2698. // complete the operation.
  2699. // returns true if more operations are operations are needed to complete the upload
  2700. try
  2701. {
  2702. Log( LOG_INFO, "Complete Async Read, Connection %p, Buffer %u, Offset %I64u, Length %u, Error %u",
  2703. m_Request->m_ExtensionControlBlock->ConnID,
  2704. m_ReadBuffer,
  2705. m_ReadOffset,
  2706. BytesRead,
  2707. dwError );
  2708. m_TotalBytesRead += BytesRead;
  2709. if ( m_ErrorValid )
  2710. throw ServerException( m_Error );
  2711. m_ReadPending = false;
  2712. if ( dwError )
  2713. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  2714. IOBuffer *Buffer = m_IOBuffers + m_ReadBuffer;
  2715. Buffer->m_BufferUsed = BytesRead;
  2716. m_BytesToRead -= BytesRead;
  2717. m_ReadOffset += BytesRead;
  2718. bool ScheduledIO = false;
  2719. if ( m_BytesToDrain )
  2720. m_BytesToDrain -= BytesRead;
  2721. else
  2722. {
  2723. m_BuffersToWrite++;
  2724. m_ReadBuffer = (m_ReadBuffer + 1 ) % NUMBER_OF_IO_BUFFERS;
  2725. }
  2726. StartupIO(); // Continue IO
  2727. }
  2728. catch( ServerException Error )
  2729. {
  2730. Log( LOG_ERROR, "Error in read complete" );
  2731. HandleError( Error );
  2732. }
  2733. catch( ComError Error )
  2734. {
  2735. Log( LOG_ERROR, "Error in read complete" );
  2736. HandleError( Error );
  2737. }
  2738. }
  2739. DWORD
  2740. AsyncReader::StartupIOWraper( LPVOID Context )
  2741. {
  2742. AsyncReader *Reader = (AsyncReader*)Context;
  2743. {
  2744. CriticalSectionLock CSLock( &Reader->m_Request->m_cs );
  2745. Reader->m_OperationsPending--;
  2746. // Thread pool threads should start and end with no token
  2747. BITSSetCurrentThreadToken( Reader->m_ThreadToken );
  2748. Reader->StartupIO();
  2749. }
  2750. Reader->m_Request->Release();
  2751. // revert to previous impersonation.
  2752. BITSSetCurrentThreadToken( NULL );
  2753. return 0;
  2754. }
  2755. void CALLBACK
  2756. AsyncReader::WriteCompleteWraper(
  2757. DWORD dwErrorCode,
  2758. DWORD dwNumberOfBytesTransfered,
  2759. LPOVERLAPPED lpOverlapped )
  2760. {
  2761. // Wrapper around write completions
  2762. Log( LOG_INFO, "WriteCompleteWraper begin" );
  2763. AsyncReader *Reader = (AsyncReader*)lpOverlapped;
  2764. {
  2765. CriticalSectionLock CSLock( &Reader->m_Request->m_cs );
  2766. Reader->m_OperationsPending--;
  2767. // Thread pool threads should start and end with no token
  2768. BITSSetCurrentThreadToken( Reader->m_ThreadToken );
  2769. Reader->WriteComplete( dwErrorCode, dwNumberOfBytesTransfered );
  2770. }
  2771. Reader->m_Request->Release();
  2772. // revert to previous security
  2773. BITSSetCurrentThreadToken( NULL );
  2774. }
  2775. void WINAPI
  2776. AsyncReader::ReadCompleteWraper(
  2777. LPEXTENSION_CONTROL_BLOCK,
  2778. PVOID pContext,
  2779. DWORD cbIO,
  2780. DWORD dwError )
  2781. {
  2782. // wrapper around read completions
  2783. Log( LOG_INFO, "ReadCompleteWraper begin" );
  2784. AsyncReader *Reader = (AsyncReader*)pContext;
  2785. {
  2786. CriticalSectionLock CSLock( &Reader->m_Request->m_cs );
  2787. Reader->m_OperationsPending--;
  2788. #if defined( DBG )
  2789. {
  2790. HANDLE ThreadToken = NULL;
  2791. ASSERT( OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &ThreadToken ) );
  2792. if ( ThreadToken )
  2793. CloseHandle( ThreadToken );
  2794. }
  2795. #endif
  2796. Reader->ReadComplete( dwError, cbIO );
  2797. }
  2798. Reader->m_Request->Release();
  2799. }
  2800. bool g_ExtensionRunning = false;
  2801. class ConfigurationManager *g_ConfigMan = NULL;
  2802. class PropertyIDManager *g_PropertyMan = NULL;
  2803. BOOL WINAPI
  2804. GetExtensionVersion(
  2805. OUT HSE_VERSION_INFO * pVer
  2806. )
  2807. {
  2808. // IIS calls this to start everything up.
  2809. HRESULT Hr = S_OK;
  2810. ASSERT( !g_ExtensionRunning );
  2811. pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
  2812. HSE_VERSION_MAJOR );
  2813. StringCbCopyA(
  2814. pVer->lpszExtensionDesc,
  2815. sizeof( pVer->lpszExtensionDesc ),
  2816. "BITS Server Extensions" );
  2817. if ( g_ExtensionRunning )
  2818. return true;
  2819. Hr = LogInit();
  2820. if ( FAILED( Hr ) )
  2821. {
  2822. SetLastError( Hr );
  2823. return false;
  2824. }
  2825. Log( LOG_INFO, "GetExtensionVersion called, starting init" );
  2826. try
  2827. {
  2828. Log( LOG_INFO, "Initializing Property Manager..." );
  2829. g_PropertyMan = new PropertyIDManager();
  2830. HRESULT Hr2 =
  2831. g_PropertyMan->LoadPropertyInfo();
  2832. if ( FAILED(Hr2) )
  2833. throw ServerException( Hr2 );
  2834. Log( LOG_INFO, "Initializing Configuration Manager..." );
  2835. g_ConfigMan = new ConfigurationManager();
  2836. }
  2837. catch( ComError & Exception )
  2838. {
  2839. Log( LOG_ERROR, "Error during initialization, 0x%8.8X", Exception.m_Hr );
  2840. delete g_ConfigMan;
  2841. delete g_PropertyMan;
  2842. LogClose();
  2843. SetLastError( Exception.m_Hr );
  2844. return false;
  2845. }
  2846. g_ExtensionRunning = true;
  2847. Log( LOG_INFO, "Initialization complete!" );
  2848. return true;
  2849. }
  2850. BOOL WINAPI
  2851. TerminateExtension(
  2852. IN DWORD dwFlags
  2853. )
  2854. {
  2855. //
  2856. // IIS calls this to shut everything down.
  2857. //
  2858. if ( !g_ExtensionRunning )
  2859. return true;
  2860. Log( LOG_INFO, "Shuting down config manager..." );
  2861. delete g_ConfigMan;
  2862. g_ConfigMan = NULL;
  2863. Log( LOG_INFO, "Shuting down property manager..." );
  2864. delete g_PropertyMan;
  2865. g_PropertyMan = NULL;
  2866. Log( LOG_INFO, "Closing logging, goodbye" );
  2867. LogClose();
  2868. g_ExtensionRunning = false;
  2869. return true;
  2870. }
  2871. DWORD WINAPI
  2872. HttpExtensionProc(
  2873. IN EXTENSION_CONTROL_BLOCK * pECB
  2874. )
  2875. {
  2876. //
  2877. // IIS calls this function for each request that is forwarded by the filter.
  2878. //
  2879. DWORD Result = HSE_STATUS_ERROR;
  2880. ServerRequest *Request = NULL;
  2881. try
  2882. {
  2883. g_LastRequest = Request = new ServerRequest( pECB );
  2884. Request->DispatchRequest();
  2885. Result = Request->IsPending() ? HSE_STATUS_PENDING : HSE_STATUS_SUCCESS;
  2886. }
  2887. catch( ServerException Exception )
  2888. {
  2889. IISLogger Logger( pECB );
  2890. Logger.LogError( Exception );
  2891. Result = HSE_STATUS_ERROR;
  2892. }
  2893. catch( ComError Exception )
  2894. {
  2895. IISLogger Logger( pECB );
  2896. Logger.LogError( Exception );
  2897. Result = HSE_STATUS_ERROR;
  2898. }
  2899. if ( Request )
  2900. Request->Release();
  2901. return Result;
  2902. }
  2903. HMODULE g_hinst;
  2904. BOOL WINAPI
  2905. DllMain(
  2906. IN HINSTANCE hinstDll,
  2907. IN DWORD dwReason,
  2908. IN LPVOID lpvContext
  2909. )
  2910. /*++
  2911. Function : DllMain
  2912. Description:
  2913. The initialization function for this DLL.
  2914. Arguments:
  2915. hinstDll - Instance handle of the DLL
  2916. dwReason - Reason why NT called this DLL
  2917. lpvContext - Reserved parameter for future use
  2918. Return Value:
  2919. Returns TRUE if successfull; otherwise FALSE.
  2920. --*/
  2921. {
  2922. // Note that appropriate initialization and termination code
  2923. // would be written within the switch statement below. Because
  2924. // this example is very simple, none is currently needed.
  2925. switch( dwReason ) {
  2926. case DLL_PROCESS_ATTACH:
  2927. g_hinst = hinstDll;
  2928. break;
  2929. case DLL_PROCESS_DETACH:
  2930. break;
  2931. }
  2932. return(TRUE);
  2933. }
  2934. #include "bitssrvcfgimp.h"