Source code of Windows XP (NT5)
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.

3193 lines
83 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. #if defined( USE_WININET )
  13. typedef StringHandleA HTTPStackStringHandle;
  14. typedef char HTTP_STRING_TYPE;
  15. #define HTTP_STRING( X ) X
  16. #else
  17. typedef StringHandleW HTTPStackStringHandle;
  18. typedef WCHAR HTTP_STRING_TYPE;
  19. #define HTTP_STRING( X ) L ## X
  20. #endif
  21. const DWORD SERVER_REQUEST_SPINLOCK = 0x80000040;
  22. const DWORD ASYNC_READER_SPINLOCK = 0x80000040;
  23. const char * const UPLOAD_PROTOCOL_STRING_V1 = "{7df0354d-249b-430f-820d-3d2a9bef4931}";
  24. // packet types that are sent in the protocol
  25. const char * const PACKET_TYPE_CREATE_SESSION = "Create-Session";
  26. const char * const PACKET_TYPE_FRAGMENT = "Fragment";
  27. const char * const PACKET_TYPE_CLOSE_SESSION = "Close-Session";
  28. const char * const PACKET_TYPE_CANCEL_SESSION = "Cancel-Session";
  29. const char * const PACKET_TYPE_PING = "Ping";
  30. //
  31. // IISLogger
  32. //
  33. // Manages the circular debugging log.
  34. //
  35. class IISLogger
  36. {
  37. EXTENSION_CONTROL_BLOCK *m_ExtensionControlBlock;
  38. void LogString( const char *String, int Size );
  39. public:
  40. IISLogger( EXTENSION_CONTROL_BLOCK *ExtensionControlBlock ) :
  41. m_ExtensionControlBlock( ExtensionControlBlock )
  42. {
  43. }
  44. void LogError( ServerException Error );
  45. void LogError( const GUID & SessionID, ServerException Error );
  46. void LogNewSession( const GUID & SessionID );
  47. void LogUploadComplete( const GUID & SessionID, UINT64 FileSize );
  48. void LogSessionClose( const GUID & SessionID );
  49. void LogSessionCancel( const GUID & SessionID );
  50. void LogExecuteEnabled();
  51. };
  52. class CriticalSectionLock
  53. {
  54. CRITICAL_SECTION* m_cs;
  55. public:
  56. CriticalSectionLock( CRITICAL_SECTION *cs ) :
  57. m_cs( cs )
  58. {
  59. EnterCriticalSection( m_cs );
  60. }
  61. ~CriticalSectionLock()
  62. {
  63. LeaveCriticalSection( m_cs );
  64. }
  65. };
  66. class AsyncReader;
  67. //
  68. // ServerRequest
  69. //
  70. // Contains all data needed to service a request. A request is a single POST not a single
  71. // upload.
  72. class ServerRequest : IISLogger
  73. {
  74. public:
  75. ServerRequest( EXTENSION_CONTROL_BLOCK * ExtensionControlBlock );
  76. ~ServerRequest();
  77. long AddRef();
  78. long Release();
  79. bool IsPending() { return m_IsPending; }
  80. // The do it function!
  81. void DispatchRequest();
  82. friend AsyncReader;
  83. private:
  84. long m_refs;
  85. CRITICAL_SECTION m_cs;
  86. bool m_IsPending;
  87. EXTENSION_CONTROL_BLOCK *m_ExtensionControlBlock;
  88. AsyncReader *m_AsyncReader;
  89. // Filled in by dispatch Request
  90. StringHandle m_PacketType;
  91. // Variables filled in by CrackPhysicalPath
  92. StringHandle m_PhysicalPath; // Path part of PathTranslated
  93. StringHandle m_PhysicalFile; // File part of PathTranslated
  94. StringHandle m_PhysicalPathAndFile; // All of PathTranslated
  95. StringHandle m_ConnectionsDirectory; // Path of the BITS connections directory
  96. StringHandle m_ConnectionDirectory; // Path of the connection directory for this connection
  97. StringHandle m_CacheFileDirectoryAndFile; // Full file path of cache file
  98. StringHandle m_ResponseFileDirectoryAndFile; // Full file path of response file
  99. // Filled in by OpenCacheFile
  100. HANDLE m_CacheFile;
  101. GUID m_SessionId;
  102. StringHandle m_SessionIdString;
  103. VDirConfig *m_DirectoryConfig;
  104. void GetConfig();
  105. StringHandle GetServerVariable( char *ServerVariable );
  106. bool TestServerVariable( char *ServerVariable );
  107. StringHandle GetRequestURL();
  108. void ValidateProtocol();
  109. void CrackSessionId();
  110. void CrackPhysicalPath();
  111. void OpenCacheFile();
  112. void ReopenCacheFileAsSync();
  113. void CloseCacheFile();
  114. void CrackContentRange(
  115. UINT64 & RangeStart,
  116. UINT64 & RangeLength,
  117. UINT64 & TotalLength );
  118. void ScheduleAsyncOperation(
  119. DWORD OperationID,
  120. LPVOID Buffer,
  121. LPDWORD Size,
  122. LPDWORD DataType );
  123. void CloseCancelSession();
  124. // dispatch routines
  125. void CreateSession();
  126. void AddFragment();
  127. void CloseSession();
  128. void CancelSession();
  129. void Ping();
  130. // Response handling
  131. void SendResponse( char *Format, DWORD Code = 200, ... );
  132. void SendResponse( ServerException Exception );
  133. void FinishSendingResponse();
  134. void DrainFragmentBlockComplete( DWORD cbIO, DWORD dwError );
  135. static void DrainFragmentBlockCompleteWrapper(
  136. LPEXTENSION_CONTROL_BLOCK lpECB,
  137. PVOID pContext,
  138. DWORD cbIO,
  139. DWORD dwError);
  140. void StartDrainBlock( );
  141. void DrainData();
  142. StringHandle m_ResponseString;
  143. DWORD m_ResponseCode;
  144. HRESULT m_ResponseHRESULT;
  145. UINT64 m_BytesToDrain;
  146. UINT64 m_ContentLength;
  147. // async IO handling
  148. void CompleteIO( AsyncReader *Reader, UINT64 TotalBytesRead );
  149. void HandleIOError( AsyncReader *Reader, ServerException Error, UINT64 TotalBytesRead );
  150. // backend notification
  151. char m_NotifyBuffer[ 1024 ];
  152. void CallServerNotification( UINT64 CacheFileSize );
  153. bool TestResponseHeader( HINTERNET hRequest, const HTTP_STRING_TYPE *Header );
  154. StringHandle GetResponseHeader( HINTERNET hRequest, const HTTP_STRING_TYPE *Header );
  155. // deal with chaining
  156. static void ForwardComplete(
  157. LPEXTENSION_CONTROL_BLOCK lpECB, PVOID pContext,
  158. DWORD cbIO, DWORD dwError );
  159. void ForwardToNextISAPI();
  160. };
  161. // AsyncReader
  162. //
  163. // Manages the buffering needed to handle the async read/write operations.
  164. class AsyncReader : private OVERLAPPED
  165. {
  166. public:
  167. AsyncReader( ServerRequest *Request,
  168. UINT64 BytesToDrain,
  169. UINT64 BytesToWrite,
  170. UINT64 WriteOffset,
  171. bool IsLastBlock,
  172. HANDLE WriteHandle,
  173. char *PrereadBuffer,
  174. DWORD PrereadSize );
  175. ~AsyncReader();
  176. UINT64 GetWriteOffset()
  177. {
  178. return m_WriteOffset;
  179. }
  180. bool IsLastBlock()
  181. {
  182. return m_IsLastBlock;
  183. }
  184. private:
  185. ServerRequest *m_Request;
  186. UINT64 m_BytesToDrain;
  187. UINT64 m_WriteOffset;
  188. UINT64 m_ReadOffset;
  189. UINT64 m_BytesToWrite;
  190. UINT64 m_BytesToRead;
  191. bool m_IsLastBlock;
  192. char * m_PrereadBuffer;
  193. DWORD m_PrereadSize;
  194. UINT64 m_TotalBytesRead;
  195. HANDLE m_WriteHandle;
  196. HANDLE m_ThreadToken;
  197. char m_OperationsPending;
  198. DWORD m_ReadBuffer;
  199. DWORD m_WriteBuffer;
  200. DWORD m_BuffersToWrite;
  201. bool m_WritePending;
  202. bool m_ReadPending;
  203. bool m_ErrorValid;
  204. ServerException m_Error;
  205. const static NUMBER_OF_IO_BUFFERS = 3;
  206. struct IOBuffer
  207. {
  208. UINT64 m_BufferWriteOffset;
  209. DWORD m_BufferUsed;
  210. char m_Buffer[ 32768 ];
  211. } m_IOBuffers[ NUMBER_OF_IO_BUFFERS ];
  212. void HandleError( ServerException Error );
  213. void CompleteIO();
  214. void StartReadRequest();
  215. void StartWriteRequest();
  216. void StartupIO( );
  217. void WriteComplete( DWORD dwError, DWORD BytesWritten );
  218. void ReadComplete( DWORD dwError, DWORD BytesRead );
  219. static DWORD StartupIOWraper( LPVOID Context );
  220. static void CALLBACK WriteCompleteWraper( DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped );
  221. static void WINAPI ReadCompleteWraper( LPEXTENSION_CONTROL_BLOCK, PVOID pContext, DWORD cbIO, DWORD dwError );
  222. };
  223. ServerRequest::ServerRequest(
  224. EXTENSION_CONTROL_BLOCK * ExtensionControlBlock
  225. ) :
  226. IISLogger( ExtensionControlBlock ),
  227. m_refs(1),
  228. m_IsPending( false ),
  229. m_ExtensionControlBlock( ExtensionControlBlock ),
  230. m_AsyncReader( NULL ),
  231. m_CacheFile( INVALID_HANDLE_VALUE ),
  232. m_DirectoryConfig( NULL ),
  233. m_ResponseCode( 0 ),
  234. m_ResponseHRESULT( 0 ),
  235. m_BytesToDrain( 0 ),
  236. m_ContentLength( 0 )
  237. {
  238. memset( &m_SessionId, 0, sizeof(m_SessionId) );
  239. if ( !InitializeCriticalSectionAndSpinCount( &m_cs, SERVER_REQUEST_SPINLOCK ) )
  240. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  241. }
  242. ServerRequest::~ServerRequest()
  243. {
  244. // The destructor handles most of the cleanup.
  245. Log( LOG_CALLEND, "Connection: %p, Packet-Type: %s, Method: %s, Path %s, HTTPError: %u, HRESULT: 0x%8.8X",
  246. m_ExtensionControlBlock->ConnID,
  247. (const char*)m_PacketType,
  248. m_ExtensionControlBlock->lpszMethod,
  249. static_cast<const char*>( m_PhysicalPathAndFile ),
  250. m_ResponseCode,
  251. m_ResponseHRESULT );
  252. delete m_AsyncReader;
  253. CloseCacheFile();
  254. if ( m_DirectoryConfig )
  255. m_DirectoryConfig->Release();
  256. DeleteCriticalSection( &m_cs );
  257. if ( m_IsPending )
  258. {
  259. Log( LOG_INFO, "Ending session" );
  260. (*m_ExtensionControlBlock->ServerSupportFunction)
  261. ( m_ExtensionControlBlock->ConnID,
  262. HSE_REQ_DONE_WITH_SESSION,
  263. NULL,
  264. NULL,
  265. NULL );
  266. }
  267. }
  268. long
  269. ServerRequest::AddRef()
  270. {
  271. long Result = InterlockedIncrement( &m_refs );
  272. ASSERT( Result > 0 );
  273. return Result;
  274. }
  275. long
  276. ServerRequest::Release()
  277. {
  278. long Result = InterlockedDecrement( &m_refs );
  279. ASSERT( Result >= 0 );
  280. if ( !Result )
  281. delete this;
  282. return Result;
  283. }
  284. StringHandle
  285. ServerRequest::GetServerVariable(
  286. char * ServerVariable )
  287. {
  288. //
  289. // Retrive a server variable from IIS. Throws an exception
  290. // is the variable can not be retrieved.
  291. //
  292. DWORD SizeOfBuffer = 0;
  293. BOOL Result = (*m_ExtensionControlBlock->GetServerVariable)
  294. ( m_ExtensionControlBlock->ConnID,
  295. ServerVariable,
  296. NULL,
  297. &SizeOfBuffer );
  298. if ( Result )
  299. return StringHandle();
  300. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  301. {
  302. Log( LOG_ERROR, "Unable to lookup server variable %s, error %x",
  303. ServerVariable,
  304. HRESULT_FROM_WIN32( GetLastError() ) );
  305. throw ServerException( HRESULT_FROM_WIN32(GetLastError()) );
  306. }
  307. StringHandle WorkString;
  308. char *Buffer = WorkString.AllocBuffer( SizeOfBuffer );
  309. Result = (*m_ExtensionControlBlock->GetServerVariable)
  310. ( m_ExtensionControlBlock->ConnID,
  311. ServerVariable,
  312. Buffer,
  313. &SizeOfBuffer );
  314. if ( !Result )
  315. {
  316. Log( LOG_ERROR, "Unable to lookup server variable %s, error %x",
  317. ServerVariable,
  318. HRESULT_FROM_WIN32( GetLastError() ) );
  319. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  320. }
  321. WorkString.SetStringSize();
  322. return WorkString;
  323. }
  324. bool
  325. ServerRequest::TestServerVariable(
  326. char *ServerVariable )
  327. {
  328. // Test for the existence of a server variable.
  329. // Returns true if the variable exists, and false if it doesn't.
  330. // throw an exception on an error.
  331. DWORD SizeOfBuffer = 0;
  332. BOOL Result = (*m_ExtensionControlBlock->GetServerVariable)
  333. ( m_ExtensionControlBlock->ConnID,
  334. ServerVariable,
  335. NULL,
  336. &SizeOfBuffer );
  337. if ( Result )
  338. return true;
  339. DWORD dwError = GetLastError();
  340. if ( ERROR_INVALID_INDEX == dwError ||
  341. ERROR_NO_DATA == dwError )
  342. return false;
  343. if ( ERROR_INSUFFICIENT_BUFFER == dwError )
  344. return true;
  345. Log( LOG_ERROR, "Unable to test server variable %s, error %x",
  346. ServerVariable,
  347. HRESULT_FROM_WIN32( GetLastError() ) );
  348. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  349. }
  350. StringHandle
  351. ServerRequest::GetRequestURL()
  352. {
  353. // Recreate the request URL from the information available from IIS.
  354. // This may not always be possible, but do the best that we can do.
  355. StringHandle ServerName = GetServerVariable("SERVER_NAME");
  356. StringHandle ServerPort = GetServerVariable("SERVER_PORT");
  357. StringHandle URL = GetServerVariable("URL");
  358. StringHandle HTTPS = GetServerVariable("HTTPS");
  359. StringHandle QueryString = GetServerVariable("QUERY_STRING");
  360. StringHandle RequestURL;
  361. if ( _stricmp( HTTPS, "on" ) == 0 )
  362. RequestURL = "https://";
  363. else
  364. RequestURL = "http://";
  365. RequestURL += ServerName;
  366. RequestURL += ":";
  367. RequestURL += ServerPort;
  368. RequestURL += URL;
  369. if ( QueryString.Size() > 0 )
  370. {
  371. RequestURL += "?";
  372. RequestURL += QueryString;
  373. }
  374. return BITSUrlCanonicalize( RequestURL, URL_ESCAPE_UNSAFE );
  375. }
  376. void
  377. ServerRequest::FinishSendingResponse()
  378. {
  379. // Completes the response. The response is taken from the buffer and
  380. // sent to the client via IIS. The choice to cancel or keep-alive the
  381. // connection made by IIS.
  382. Log( LOG_INFO, "Finish sending response" );
  383. // Close the cache before sending the response in case the client starts a new request immediatly.
  384. CloseCacheFile();
  385. // Finish sending the response using the information
  386. // in m_ResponseBuffer and m_ResponseCode.
  387. // If an error occures, give up and force a disconnect.
  388. m_ExtensionControlBlock->dwHttpStatusCode = m_ResponseCode;
  389. BOOL Result;
  390. BOOL KeepConnection;
  391. Result =
  392. (m_ExtensionControlBlock->ServerSupportFunction)(
  393. m_ExtensionControlBlock->ConnID,
  394. HSE_REQ_IS_KEEP_CONN,
  395. &KeepConnection,
  396. NULL,
  397. NULL );
  398. if ( !Result )
  399. {
  400. // Error occured quering the disconnect setting. Assume
  401. // a disconnect.
  402. KeepConnection = 0;
  403. }
  404. // IIS5.0(Win2k) has a bug where KeepConnect is returned as -1
  405. // to keep the connection alive. Apparently, this confuses the
  406. // HSE_REQ_SEND_RESPONSE_HEADER_EX call. Bash the value into a real bool.
  407. KeepConnection = KeepConnection ? 1 : 0;
  408. HSE_SEND_HEADER_EX_INFO HeaderInfo;
  409. HeaderInfo.pszStatus = LookupHTTPStatusCodeText( m_ResponseCode );
  410. HeaderInfo.cchStatus = strlen( HeaderInfo.pszStatus );
  411. HeaderInfo.pszHeader = (const char*)m_ResponseString;
  412. HeaderInfo.cchHeader = (DWORD)m_ResponseString.Size();
  413. HeaderInfo.fKeepConn = KeepConnection;
  414. Result =
  415. (m_ExtensionControlBlock->ServerSupportFunction)(
  416. m_ExtensionControlBlock->ConnID,
  417. HSE_REQ_SEND_RESPONSE_HEADER_EX,
  418. &HeaderInfo,
  419. NULL,
  420. NULL );
  421. if ( !Result )
  422. {
  423. Log( LOG_ERROR, "Unable to send response, error %x",
  424. HRESULT_FROM_WIN32( GetLastError() ) );
  425. Log( LOG_INFO, "Forcing the connection closed" );
  426. // Couldn't send the response, attempt to close the connection
  427. Result =
  428. (m_ExtensionControlBlock->ServerSupportFunction)(
  429. m_ExtensionControlBlock->ConnID,
  430. HSE_REQ_CLOSE_CONNECTION,
  431. NULL,
  432. NULL,
  433. NULL );
  434. if ( !Result )
  435. {
  436. // The close connection request failed. No choice but to invoke
  437. // the hammer of death
  438. (m_ExtensionControlBlock->ServerSupportFunction)(
  439. m_ExtensionControlBlock->ConnID,
  440. HSE_REQ_ABORTIVE_CLOSE,
  441. NULL,
  442. NULL,
  443. NULL );
  444. }
  445. }
  446. }
  447. void
  448. ServerRequest::SendResponse( char *Format, DWORD Code, ...)
  449. {
  450. // Starts the sending of a response. Unfortunatly, many HTTP
  451. // client stacks do not handle a response being returned while
  452. // data is still being sent. To handle this, it is necessary
  453. // to capture the response to a buffer. Then after all the sent data
  454. // is drained, finally send the response.
  455. va_list arglist;
  456. va_start( arglist, Code );
  457. SIZE_T ResponseBufferSize = 512;
  458. while( 1 )
  459. {
  460. char * ResponseBuffer = m_ResponseString.AllocBuffer( ResponseBufferSize );
  461. HRESULT Hr =
  462. StringCchVPrintfA(
  463. ResponseBuffer,
  464. ResponseBufferSize,
  465. Format,
  466. arglist );
  467. if ( SUCCEEDED( Hr ) )
  468. {
  469. m_ResponseString.SetStringSize();
  470. break;
  471. }
  472. else if ( STRSAFE_E_INSUFFICIENT_BUFFER == Hr )
  473. ResponseBufferSize *= 2;
  474. else
  475. throw ServerException( Hr );
  476. if ( ResponseBufferSize >= 0xFFFFFFFF )
  477. throw ServerException( E_INVALIDARG );
  478. }
  479. m_ResponseCode = Code;
  480. // Drain data in error cases, othersize assume that
  481. // we already drained all the data.
  482. if ( Code >= 400 )
  483. {
  484. // This is an error case. Drain the data first, then send
  485. // the response.
  486. Log( LOG_INFO, "HTTP status >= 400, draining data" );
  487. try
  488. {
  489. // start draining data. DrainData() calls FinishSendingResponse
  490. // when it is finished.
  491. DrainData();
  492. }
  493. catch( ServerException Exception )
  494. {
  495. // something is very broken, and an attempt to drain excess data
  496. // failed. Nothing else to do except try sending the response.
  497. FinishSendingResponse();
  498. }
  499. return;
  500. }
  501. else
  502. {
  503. // Just send the response since we already handled draining
  504. FinishSendingResponse();
  505. }
  506. }
  507. void
  508. ServerRequest::SendResponse( ServerException Exception )
  509. {
  510. // Starts the sending of a response. Unfortunatly, many HTTP
  511. // client stacks do not handle a response being returned while
  512. // data is still being sent. To handle this, it is necessary
  513. // to capture the response to a buffer. Then after all the sent data
  514. // is drained, finally send the response.
  515. GUID NullGuid;
  516. memset( &NullGuid, 0, sizeof( NullGuid ) );
  517. if ( memcmp( &NullGuid, &m_SessionId, sizeof( NullGuid ) ) == 0 )
  518. LogError( Exception );
  519. else
  520. LogError( m_SessionId, Exception );
  521. SIZE_T ResponseBufferSize = 512;
  522. while( 1 )
  523. {
  524. char * ResponseBuffer = m_ResponseString.AllocBuffer( ResponseBufferSize );
  525. HRESULT Hr =
  526. StringCchPrintfA(
  527. ResponseBuffer,
  528. ResponseBufferSize,
  529. "Pragma: no-cache\r\n"
  530. "BITS-packet-type: Ack\r\n"
  531. "BITS-Error: 0x%8.8X\r\n"
  532. "BITS-Error-Context: 0x%X\r\n"
  533. "\r\n",
  534. Exception.GetCode(),
  535. Exception.GetContext() );
  536. if ( SUCCEEDED( Hr ) )
  537. {
  538. m_ResponseString.SetStringSize();
  539. break;
  540. }
  541. else if ( STRSAFE_E_INSUFFICIENT_BUFFER == Hr )
  542. ResponseBufferSize *= 2;
  543. else
  544. throw ServerException( Hr );
  545. if ( ResponseBufferSize >= 0xFFFFFFFF )
  546. throw ServerException( E_INVALIDARG );
  547. }
  548. m_ResponseCode = Exception.GetHttpCode();
  549. m_ResponseHRESULT = Exception.GetCode();
  550. Log( LOG_INFO, "Sending error response of HRESULT: 0x%8.8X, HTTP status: %d",
  551. m_ResponseHRESULT, m_ResponseCode );
  552. try
  553. {
  554. DrainData();
  555. }
  556. catch( ServerException Exception )
  557. {
  558. FinishSendingResponse();
  559. }
  560. }
  561. void
  562. ServerRequest::DrainFragmentBlockComplete(
  563. DWORD cbIO,
  564. DWORD dwError )
  565. {
  566. // A drain block has been completed. If this is the last block, finish sending the response.
  567. // Otherwise,
  568. Log( LOG_INFO, "Drain fragment complete, cbIO: %u, dwError: %u", cbIO, dwError );
  569. m_BytesToDrain -= cbIO;
  570. if ( !m_BytesToDrain || !cbIO || dwError )
  571. {
  572. FinishSendingResponse();
  573. return;
  574. }
  575. try
  576. {
  577. StartDrainBlock();
  578. }
  579. catch( ServerException Exception )
  580. {
  581. // An error occured while draining data, exit
  582. FinishSendingResponse();
  583. }
  584. }
  585. void
  586. ServerRequest::DrainFragmentBlockCompleteWrapper(
  587. LPEXTENSION_CONTROL_BLOCK lpECB,
  588. PVOID pContext,
  589. DWORD cbIO,
  590. DWORD dwError)
  591. {
  592. // Wrapper, handles critical section
  593. ServerRequest *This = (ServerRequest*)pContext;
  594. {
  595. CriticalSectionLock CSLock( &This->m_cs );
  596. This->DrainFragmentBlockComplete( cbIO, dwError );
  597. }
  598. This->Release();
  599. }
  600. void
  601. ServerRequest::StartDrainBlock( )
  602. {
  603. // start the next block to drain.
  604. BOOL Result;
  605. static char s_Buffer[ 32768 ];
  606. DWORD ReadSize = (DWORD)min( 0xFFFFFFFF, min( m_BytesToDrain, sizeof( s_Buffer ) ) );
  607. DWORD Flags = HSE_IO_ASYNC;
  608. Log( LOG_INFO, "Starting next drain block of %u bytes", ReadSize );
  609. ScheduleAsyncOperation(
  610. HSE_REQ_ASYNC_READ_CLIENT,
  611. (LPVOID)s_Buffer,
  612. &ReadSize,
  613. &Flags );
  614. }
  615. void
  616. ServerRequest::DrainData()
  617. {
  618. // Make the decission regarding the amount of data to drain
  619. // and the start the first block
  620. if ( m_DirectoryConfig )
  621. m_BytesToDrain = min( m_BytesToDrain, m_DirectoryConfig->m_MaxFileSize );
  622. else
  623. // use an internal max of 4KB
  624. m_BytesToDrain = min( 4096, m_BytesToDrain );
  625. if ( !m_BytesToDrain )
  626. {
  627. Log( LOG_INFO, "No bytes to drain, finish it" );
  628. FinishSendingResponse();
  629. return;
  630. }
  631. Log( LOG_INFO, "Starting pipe drain" );
  632. BOOL Result;
  633. Result =
  634. (*m_ExtensionControlBlock->ServerSupportFunction)(
  635. m_ExtensionControlBlock->ConnID,
  636. HSE_REQ_IO_COMPLETION,
  637. (LPVOID)DrainFragmentBlockCompleteWrapper,
  638. 0,
  639. (LPDWORD)this );
  640. if ( !Result )
  641. {
  642. Log( LOG_ERROR, "Error settings callback, error %x",
  643. HRESULT_FROM_WIN32( GetLastError() ) );
  644. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  645. }
  646. StartDrainBlock();
  647. }
  648. void
  649. ServerRequest::ValidateProtocol()
  650. {
  651. // Negotiate the protocol with the client. The client sends a list of
  652. // supported protocols to the server and the server picks the best protocol.
  653. // For now, only one protocol is supported.
  654. StringHandle SupportedProtocolsHandle = GetServerVariable( "HTTP_BITS-SUPPORTED-PROTOCOLS" );
  655. WorkStringBuffer SupportedProtocolsBuffer( (const char*) SupportedProtocolsHandle );
  656. char *SupportedProtocols = SupportedProtocolsBuffer.GetBuffer();
  657. char *Protocol = strtok( SupportedProtocols, " ," );
  658. while( Protocol )
  659. {
  660. if ( _stricmp( Protocol, UPLOAD_PROTOCOL_STRING_V1 ) == 0 )
  661. {
  662. Log( LOG_INFO, "Detected protocol upload protocol V1" );
  663. return;
  664. }
  665. Protocol = strtok( NULL, " ," );
  666. }
  667. Log( LOG_INFO, "Unsupported protocols, %s", (const char*)SupportedProtocols );
  668. throw ServerException( E_INVALIDARG );
  669. }
  670. void
  671. ServerRequest::CrackSessionId()
  672. {
  673. // Convert the session ID from a string into a GUID.
  674. StringHandle SessionId = GetServerVariable( "HTTP_BITS-Session-Id" );
  675. m_SessionId = BITSGuidFromString( SessionId );
  676. m_SessionIdString = BITSStringFromGuid( m_SessionId );
  677. }
  678. void
  679. ServerRequest::CrackContentRange(
  680. UINT64 & RangeStart,
  681. UINT64 & RangeLength,
  682. UINT64 & TotalLength )
  683. {
  684. // Crack the content range header which contains the client's view of where the
  685. // upload is at.
  686. StringHandle ContentRange = GetServerVariable( "HTTP_Content-Range" );
  687. UINT64 RangeEnd;
  688. int ReturnVal = sscanf( ContentRange, " bytes %I64u - %I64u / %I64u ",
  689. &RangeStart, &RangeEnd, &TotalLength );
  690. if ( TotalLength > m_DirectoryConfig->m_MaxFileSize )
  691. {
  692. Log( LOG_ERROR, "Size of the upload at %I64u is greater then the maximum of %I64u",
  693. TotalLength, m_DirectoryConfig->m_MaxFileSize );
  694. throw ServerException( BG_E_TOO_LARGE );
  695. }
  696. if ( ReturnVal != 3 )
  697. {
  698. Log( LOG_ERROR, "Range has %d elements instead of the expected number of 3", ReturnVal );
  699. throw ServerException( E_INVALIDARG );
  700. }
  701. if ( ( RangeStart == RangeEnd + 1 ) &&
  702. ( 0 == m_ContentLength ) &&
  703. ( RangeStart == TotalLength ) )
  704. {
  705. // Continue after a failed notification
  706. RangeStart = TotalLength;
  707. RangeLength = 0;
  708. return;
  709. }
  710. if ( RangeEnd < RangeStart )
  711. {
  712. Log( LOG_ERROR, "Range start is greater then the range length, End %I64u, Start %I64u",
  713. RangeEnd, RangeStart );
  714. throw ServerException( E_INVALIDARG );
  715. }
  716. RangeLength = RangeEnd - RangeStart + 1;
  717. if ( m_ContentLength != RangeLength )
  718. {
  719. Log( LOG_ERROR, "The content length is different from the range length. Content %I64u, Range %I64u",
  720. m_ContentLength, RangeLength );
  721. throw ServerException( E_INVALIDARG );
  722. }
  723. }
  724. void
  725. ServerRequest::ScheduleAsyncOperation(
  726. DWORD OperationID,
  727. LPVOID Buffer,
  728. LPDWORD Size,
  729. LPDWORD DataType )
  730. {
  731. // start an async operation and handle all the flags and recounting required.
  732. BOOL Result;
  733. AddRef();
  734. Result =
  735. (*m_ExtensionControlBlock->ServerSupportFunction)(
  736. m_ExtensionControlBlock->ConnID,
  737. OperationID,
  738. Buffer,
  739. Size,
  740. DataType );
  741. if ( !Result )
  742. {
  743. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  744. Log( LOG_ERROR, "Error starting async operation, error %x", Hr );
  745. // Operation was never scheduled, remove the callbacks refcount
  746. Release();
  747. throw ServerException( Hr );
  748. }
  749. m_IsPending = true;
  750. }
  751. // dispatch routines
  752. void
  753. ServerRequest::CreateSession()
  754. {
  755. // Handles the Create-Session command from the client.
  756. // Create a new session and all the directories required to
  757. // support that session.
  758. ValidateProtocol();
  759. m_SessionId = BITSCreateGuid();
  760. m_SessionIdString = BITSStringFromGuid( m_SessionId );
  761. CrackPhysicalPath();
  762. BITSCreateDirectory( (LPCTSTR)m_ConnectionsDirectory );
  763. try
  764. {
  765. // Need to create directories in a loop since another thread could
  766. // delete the connections directory just as we are creating the connection
  767. // directory.
  768. while( 1 )
  769. {
  770. try
  771. {
  772. BITSCreateDirectory( m_ConnectionDirectory );
  773. break;
  774. }
  775. catch( ServerException e )
  776. {
  777. if ( e.GetCode() != HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) )
  778. throw;
  779. // Try to recreate the connections directory
  780. BITSCreateDirectory( (LPCTSTR)m_ConnectionsDirectory );
  781. }
  782. }
  783. OpenCacheFile( );
  784. }
  785. catch( ServerException e )
  786. {
  787. RemoveDirectory( m_ConnectionDirectory );
  788. RemoveDirectory( m_ConnectionsDirectory );
  789. throw;
  790. }
  791. if ( m_DirectoryConfig->m_HostId.Size() )
  792. {
  793. if ( m_DirectoryConfig->m_HostIdFallbackTimeout != MD_BITS_NO_TIMEOUT )
  794. {
  795. SendResponse(
  796. "Pragma: no-cache\r\n"
  797. "BITS-Packet-Type: Ack\r\n"
  798. "BITS-Protocol: %s\r\n"
  799. "BITS-Session-Id: %s\r\n"
  800. "BITS-Host-Id: %s\r\n"
  801. "BITS-Host-Id-Fallback-Timeout: %u\r\n"
  802. "Content-Length: 0\r\n"
  803. "Accept-encoding: identity\r\n"
  804. "\r\n",
  805. 200,
  806. UPLOAD_PROTOCOL_STRING_V1,
  807. (const char*)m_SessionIdString, // SessionId
  808. (const char*)m_DirectoryConfig->m_HostId,
  809. m_DirectoryConfig->m_HostIdFallbackTimeout
  810. );
  811. }
  812. else
  813. {
  814. SendResponse(
  815. "Pragma: no-cache\r\n"
  816. "BITS-Packet-Type: Ack\r\n"
  817. "BITS-Protocol: %s\r\n"
  818. "BITS-Session-Id: %s\r\n"
  819. "BITS-Host-Id: %s\r\n"
  820. "Content-Length: 0\r\n"
  821. "Accept-encoding: identity\r\n"
  822. "\r\n",
  823. 200,
  824. UPLOAD_PROTOCOL_STRING_V1,
  825. (const char*)m_SessionIdString, // SessionId
  826. (const char*)m_DirectoryConfig->m_HostId
  827. );
  828. }
  829. }
  830. else
  831. {
  832. SendResponse(
  833. "Pragma: no-cache\r\n"
  834. "BITS-Packet-Type: Ack\r\n"
  835. "BITS-Protocol: %s\r\n"
  836. "BITS-Session-Id: %s\r\n"
  837. "Content-Length: 0\r\n"
  838. "Accept-encoding: identity\r\n"
  839. "\r\n",
  840. 200,
  841. UPLOAD_PROTOCOL_STRING_V1,
  842. (const char*)m_SessionIdString // SessionId
  843. );
  844. }
  845. LogNewSession( m_SessionId );
  846. }
  847. void
  848. ServerRequest::AddFragment()
  849. {
  850. // Handles the fragment command from the client. Opens the cache file
  851. // and resumes the upload.
  852. CrackSessionId();
  853. CrackPhysicalPath();
  854. OpenCacheFile( );
  855. UINT64 CacheFileSize = BITSGetFileSize( m_CacheFile );
  856. UINT64 RangeStart, RangeLength, TotalLength;
  857. CrackContentRange( RangeStart, RangeLength, TotalLength );
  858. if ( CacheFileSize < RangeStart )
  859. {
  860. // Can't recover from this error on the server since we have a gap.
  861. // Need to get the client to backup and start again.
  862. Log( LOG_INFO, "Client and server are hopelessly out of sync, sending the 416 error code" );
  863. SendResponse(
  864. "Pragma: no-cache\r\n"
  865. "BITS-Packet-Type: Ack\r\n"
  866. "BITS-Received-Content-Range: %I64u\r\n"
  867. "\r\n",
  868. 416,
  869. CacheFileSize );
  870. return;
  871. }
  872. if ( RangeStart + RangeLength > TotalLength )
  873. {
  874. Log( LOG_ERROR, "Range extends past end of file. Start %I64u, Length %I64u, Total %I64u",
  875. RangeStart, RangeLength, TotalLength );
  876. throw ServerException( E_INVALIDARG );
  877. }
  878. BITSSetFilePointer( m_CacheFile, 0, FILE_END );
  879. // Some thought cases for these formulas.
  880. // 1. RangeLength = 0
  881. // BytesToDrain will be 0 and BytesToWrite will be 0
  882. // 2. RangeStart = CacheFileSize ( most common case )
  883. // BytesToDrain will be 0, and BytesToWrite will be BytesToDrain
  884. // 3. RangeStart < CacheFileSize
  885. // BytesToDrain will be nonzero, and BytesToWrite will be the remainder.
  886. UINT64 BytesToDrain = min( (CacheFileSize - RangeStart), RangeLength );
  887. UINT64 BytesToWrite = RangeLength - BytesToDrain;
  888. UINT64 WriteOffset = CacheFileSize;
  889. // Start the async reader
  890. m_AsyncReader =
  891. new AsyncReader(
  892. this,
  893. BytesToDrain,
  894. BytesToWrite, // bytes to write
  895. WriteOffset, // write offset
  896. RangeStart + RangeLength == TotalLength, // if last BLOCK
  897. m_CacheFile,
  898. (char*)m_ExtensionControlBlock->lpbData,
  899. m_ExtensionControlBlock->cbAvailable );
  900. }
  901. // async IO handling
  902. void
  903. ServerRequest::CompleteIO( AsyncReader *Reader, UINT64 TotalBytesRead )
  904. {
  905. //
  906. // Called by the AsyncReader when the request finished successfully.
  907. //
  908. Log( LOG_INFO, "Async IO operation complete, finishing" );
  909. try
  910. {
  911. if ( TotalBytesRead > m_BytesToDrain )
  912. m_BytesToDrain = 0; // shouldn't happen, but just in case
  913. else
  914. m_BytesToDrain -= TotalBytesRead;
  915. UINT64 CacheFileSize = BITSGetFileSize( m_CacheFile );
  916. ASSERT( Reader->GetWriteOffset() == CacheFileSize );
  917. if ( Reader->IsLastBlock() &&
  918. BITS_NOTIFICATION_TYPE_NONE != m_DirectoryConfig->m_NotificationType )
  919. {
  920. CallServerNotification( CacheFileSize );
  921. }
  922. else
  923. {
  924. // No server notification to make
  925. SendResponse(
  926. "Pragma: no-cache\r\n"
  927. "BITS-Packet-Type: Ack\r\n"
  928. "Content-Length: 0\r\n"
  929. "BITS-Received-Content-Range: %I64u\r\n"
  930. "\r\n",
  931. 200,
  932. CacheFileSize );
  933. }
  934. if ( Reader->IsLastBlock() && TotalBytesRead )
  935. LogUploadComplete( m_SessionId, CacheFileSize );
  936. }
  937. catch( ServerException Error )
  938. {
  939. SendResponse( Error );
  940. }
  941. }
  942. void
  943. ServerRequest::HandleIOError( AsyncReader *Reader, ServerException Error, UINT64 TotalBytesRead )
  944. {
  945. //
  946. // Called by AsyncReader when a fatal error occures in processing the request
  947. //
  948. Log( LOG_ERROR, "An error occured while handling the async IO" );
  949. if ( TotalBytesRead > m_BytesToDrain )
  950. m_BytesToDrain = 0; // shouldn't happen, but just in case
  951. else
  952. m_BytesToDrain -= TotalBytesRead;
  953. SendResponse( Error );
  954. }
  955. void
  956. ServerRequest::CallServerNotification( UINT64 CacheFileSize )
  957. {
  958. // Handles notifications and all the exciting pieces to it.
  959. HINTERNET hInternet = NULL;
  960. HINTERNET hConnect = NULL;
  961. HINTERNET hRequest = NULL;
  962. HANDLE hResponseFile = INVALID_HANDLE_VALUE;
  963. Log( LOG_INFO, "Calling backend notification, type %u",
  964. m_DirectoryConfig->m_NotificationType );
  965. try
  966. {
  967. if ( BITS_NOTIFICATION_TYPE_POST_BYVAL == m_DirectoryConfig->m_NotificationType )
  968. {
  969. // only create the response file if this is a byval notification
  970. hResponseFile =
  971. CreateFile(
  972. m_ResponseFileDirectoryAndFile,
  973. GENERIC_READ | GENERIC_WRITE,
  974. 0,
  975. NULL,
  976. CREATE_ALWAYS,
  977. FILE_ATTRIBUTE_NORMAL,
  978. NULL );
  979. if ( INVALID_HANDLE_VALUE == hResponseFile )
  980. {
  981. Log( LOG_ERROR, "Unable to create the response file %s, error %x",
  982. (const char*)m_ResponseFileDirectoryAndFile,
  983. HRESULT_FROM_WIN32( GetLastError() ) );
  984. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  985. }
  986. }
  987. Log( LOG_INFO, "Connecting to backend for notification" );
  988. #if defined(USE_WININET)
  989. //
  990. // Flush cached credentials
  991. //
  992. if (!InternetSetOption(0, INTERNET_OPTION_END_BROWSER_SESSION, NULL, 0 ))
  993. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  994. #endif
  995. hInternet =
  996. InternetOpen(
  997. HTTP_STRING( "BITS Server Extensions" ),
  998. INTERNET_OPEN_TYPE_PRECONFIG,
  999. NULL,
  1000. NULL,
  1001. 0 );
  1002. if ( !hInternet )
  1003. {
  1004. Log( LOG_ERROR, "Internet open failed, error %x", HRESULT_FROM_WIN32( GetLastError() ) );
  1005. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1006. }
  1007. StringHandle RequestURL = GetRequestURL();
  1008. StringHandleW NotificationURL;
  1009. if ( m_DirectoryConfig->m_NotificationURL.Size() != 0 )
  1010. {
  1011. // if the a notification URL was set, then combine that URL with the original URL.
  1012. // Otherwise just use the original URL. This allows BITS to be used to call
  1013. // many arbitrary ASP pages.
  1014. NotificationURL = StringHandleW(
  1015. BITSUrlCombine( RequestURL, m_DirectoryConfig->m_NotificationURL,
  1016. URL_ESCAPE_UNSAFE ) );
  1017. }
  1018. else
  1019. {
  1020. NotificationURL = StringHandleW( RequestURL );
  1021. }
  1022. Log( LOG_INFO, "Request URL: %s", (const char*)StringHandle( RequestURL ) );
  1023. Log( LOG_INFO, "Notification URL: %s", (const char*)StringHandle( NotificationURL ) );
  1024. //
  1025. // Split the URL into server, path, name, and password components.
  1026. //
  1027. HTTPStackStringHandle HostName;
  1028. HTTPStackStringHandle UrlPath;
  1029. HTTPStackStringHandle UserName;
  1030. HTTPStackStringHandle Password;
  1031. URL_COMPONENTS UrlComponents;
  1032. ZeroMemory(&UrlComponents, sizeof(UrlComponents));
  1033. UrlComponents.dwStructSize = sizeof(UrlComponents);
  1034. UrlComponents.lpszHostName = HostName.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1035. UrlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH + 1;
  1036. UrlComponents.lpszUrlPath = UrlPath.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1037. UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH + 1;
  1038. UrlComponents.lpszUserName = UserName.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1039. UrlComponents.dwUserNameLength = INTERNET_MAX_URL_LENGTH + 1;
  1040. UrlComponents.lpszPassword = Password.AllocBuffer( INTERNET_MAX_URL_LENGTH + 1 );
  1041. UrlComponents.dwPasswordLength = INTERNET_MAX_URL_LENGTH + 1;
  1042. if ( !InternetCrackUrl(
  1043. NotificationURL,
  1044. (DWORD)NotificationURL.Size(),
  1045. 0,
  1046. &UrlComponents ) )
  1047. {
  1048. Log( LOG_ERROR, "InternetCrackURL failed, error %x", HRESULT_FROM_WIN32( GetLastError() ) );
  1049. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1050. }
  1051. HostName.SetStringSize();
  1052. UrlPath.SetStringSize();
  1053. UserName.SetStringSize();
  1054. Password.SetStringSize();
  1055. StringHandle QueryString = GetServerVariable( "QUERY_STRING" );
  1056. if ( QueryString.Size() )
  1057. {
  1058. UrlPath += HTTPStackStringHandle( StringHandle("?") );
  1059. UrlPath += HTTPStackStringHandle( QueryString );
  1060. }
  1061. if ( BITS_NOTIFICATION_TYPE_POST_BYREF == m_DirectoryConfig->m_NotificationType )
  1062. CloseCacheFile();
  1063. hConnect =
  1064. InternetConnect(
  1065. hInternet,
  1066. HostName,
  1067. UrlComponents.nPort,
  1068. UserName,
  1069. Password,
  1070. INTERNET_SERVICE_HTTP,
  1071. 0, 0 );
  1072. if ( !hConnect )
  1073. {
  1074. Log( LOG_ERROR, "InternetConnect failed, error %x", HRESULT_FROM_WIN32( GetLastError() ) );
  1075. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1076. }
  1077. const HTTP_STRING_TYPE *AcceptTypes[] = { HTTP_STRING( "*/*" ), NULL };
  1078. hRequest =
  1079. HttpOpenRequest(
  1080. hConnect,
  1081. HTTP_STRING( "POST" ),
  1082. UrlPath,
  1083. HTTP_STRING( "HTTP/1.1" ),
  1084. NULL,
  1085. AcceptTypes,
  1086. #if defined( USE_WININET )
  1087. INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD,
  1088. #else
  1089. INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD | WINHTTP_FLAG_ESCAPE_DISABLE_QUERY,
  1090. #endif
  1091. 0 );
  1092. if ( !hRequest )
  1093. {
  1094. Log( LOG_ERROR, "HttpOpenRequest failed, error %x", HRESULT_FROM_WIN32( GetLastError() ) );
  1095. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1096. }
  1097. INTERNET_BUFFERS buf = {0};
  1098. buf.dwStructSize = sizeof( INTERNET_BUFFERS );
  1099. buf.dwBufferTotal = (DWORD)CacheFileSize;
  1100. HTTPStackStringHandle AdditionalHeaders = HTTP_STRING( "BITS-Original-Request-URL: " );
  1101. AdditionalHeaders += HTTPStackStringHandle( RequestURL );
  1102. AdditionalHeaders += HTTP_STRING( "\r\n" );
  1103. if ( BITS_NOTIFICATION_TYPE_POST_BYREF == m_DirectoryConfig->m_NotificationType )
  1104. {
  1105. // Add the path to the request datafile name
  1106. AdditionalHeaders += HTTP_STRING( "BITS-Request-DataFile-Name: " );
  1107. AdditionalHeaders += HTTPStackStringHandle( m_CacheFileDirectoryAndFile );
  1108. AdditionalHeaders += HTTP_STRING( "\r\n" );
  1109. // Add the path to where to place the response datafile name
  1110. AdditionalHeaders += HTTP_STRING( "BITS-Response-DataFile-Name: " );
  1111. AdditionalHeaders += HTTPStackStringHandle( m_ResponseFileDirectoryAndFile );
  1112. AdditionalHeaders += HTTP_STRING( "\r\n" );
  1113. buf.dwBufferTotal = 0;
  1114. }
  1115. if ( !HttpAddRequestHeaders(
  1116. hRequest,
  1117. AdditionalHeaders,
  1118. (DWORD)AdditionalHeaders.Size(),
  1119. HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE ) )
  1120. {
  1121. Log( LOG_ERROR, "HttpAddRequestHeaders failed error %x",
  1122. HRESULT_FROM_WIN32( GetLastError() ) );
  1123. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1124. }
  1125. if ( buf.dwBufferTotal )
  1126. {
  1127. Log( LOG_INFO, "Sending data..." );
  1128. if ( !HttpSendRequestEx(
  1129. hRequest,
  1130. &buf,
  1131. NULL,
  1132. HSR_INITIATE,
  1133. NULL ) )
  1134. {
  1135. Log( LOG_ERROR, "HttpSendRequestEx failed error %x",
  1136. HRESULT_FROM_WIN32( GetLastError() ) );
  1137. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1138. }
  1139. ReopenCacheFileAsSync();
  1140. SetFilePointer( m_CacheFile, 0, NULL, FILE_BEGIN );
  1141. DWORD BytesRead;
  1142. DWORD TotalRead = 0;
  1143. do
  1144. {
  1145. BOOL b;
  1146. if (!(b = ReadFile (m_CacheFile,
  1147. m_NotifyBuffer,
  1148. sizeof(m_NotifyBuffer),
  1149. &BytesRead,
  1150. NULL)))
  1151. {
  1152. Log( LOG_ERROR, "ReadFile failed, error %x",
  1153. HRESULT_FROM_WIN32( GetLastError() ) );
  1154. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1155. }
  1156. TotalRead += BytesRead;
  1157. if (BytesRead > 0)
  1158. {
  1159. DWORD BytesWritten;
  1160. DWORD TotalWritten = 0;
  1161. do
  1162. {
  1163. if (!(b = InternetWriteFile( hRequest,
  1164. m_NotifyBuffer + TotalWritten,
  1165. BytesRead - TotalWritten,
  1166. &BytesWritten)))
  1167. {
  1168. Log( LOG_ERROR, "InternetWriteFile failed, error %x",
  1169. HRESULT_FROM_WIN32( GetLastError() ) );
  1170. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1171. }
  1172. TotalWritten += BytesWritten;
  1173. } while( TotalWritten != BytesRead );
  1174. }
  1175. }
  1176. while ( TotalRead < buf.dwBufferTotal );
  1177. if ( !HttpEndRequest( hRequest, NULL, 0, 0 ) )
  1178. {
  1179. Log( LOG_ERROR, "HttpEndRequest failed, error %x",
  1180. HRESULT_FROM_WIN32( GetLastError() ) );
  1181. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1182. }
  1183. }
  1184. else
  1185. {
  1186. if ( !HttpSendRequest(
  1187. hRequest,
  1188. NULL,
  1189. 0,
  1190. NULL,
  1191. 0 ) )
  1192. {
  1193. Log( LOG_ERROR, "HttpSendRequest failed, error %x",
  1194. HRESULT_FROM_WIN32( GetLastError() ) );
  1195. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0,0x7 );
  1196. }
  1197. }
  1198. //
  1199. // Check for a BITS-Static-Response-URL. If a static response is given,
  1200. // remove the response file and format URL
  1201. //
  1202. bool HasStaticResponse = TestResponseHeader( hRequest, HTTP_STRING( "BITS-Static-Response-URL" ) );
  1203. if ( HasStaticResponse )
  1204. {
  1205. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1206. {
  1207. CloseHandle( hResponseFile );
  1208. hResponseFile = INVALID_HANDLE_VALUE;
  1209. BITSDeleteFile( m_ResponseFileDirectoryAndFile );
  1210. }
  1211. }
  1212. //
  1213. // drain the pipe.
  1214. //
  1215. Log( LOG_INFO, "Processing backend response" );
  1216. DWORD dwStatus;
  1217. DWORD dwLength;
  1218. dwLength = sizeof(dwStatus);
  1219. if (! HttpQueryInfo(hRequest,
  1220. HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  1221. (LPVOID)&dwStatus,
  1222. &dwLength,
  1223. NULL))
  1224. {
  1225. Log( LOG_ERROR, "HttpQueryInfo failed, error %x",
  1226. HRESULT_FROM_WIN32( GetLastError() ) );
  1227. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1228. }
  1229. DWORD BytesRead;
  1230. DWORD BytesWritten;
  1231. do
  1232. {
  1233. if (!InternetReadFile( hRequest,
  1234. m_NotifyBuffer,
  1235. sizeof( m_NotifyBuffer ),
  1236. &BytesRead
  1237. ))
  1238. {
  1239. Log( LOG_ERROR, "InternetReadFile failed, error %x",
  1240. HRESULT_FROM_WIN32( GetLastError() ) );
  1241. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1242. }
  1243. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1244. {
  1245. if ( !WriteFile(
  1246. hResponseFile,
  1247. m_NotifyBuffer,
  1248. BytesRead,
  1249. &BytesWritten,
  1250. NULL ) )
  1251. {
  1252. Log( LOG_ERROR, "WriteFile failed, error %x",
  1253. HRESULT_FROM_WIN32( GetLastError() ) );
  1254. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ), 0, 0x7 );
  1255. }
  1256. }
  1257. }
  1258. while ( BytesRead > 0 );
  1259. //
  1260. // Retrieve or compute the reply URL( the default is to use self-relative form).
  1261. //
  1262. StringHandle ReplyURL;
  1263. if ( HasStaticResponse )
  1264. {
  1265. ReplyURL = GetResponseHeader( hRequest, HTTP_STRING( "BITS-Static-Response-URL" ) );
  1266. }
  1267. else
  1268. {
  1269. if ( INVALID_FILE_ATTRIBUTES != GetFileAttributes( m_ResponseFileDirectoryAndFile ) )
  1270. {
  1271. ReplyURL = m_DirectoryConfig->m_ConnectionsDir;
  1272. ReplyURL += "\\";
  1273. ReplyURL += m_SessionIdString;
  1274. ReplyURL += "\\";
  1275. ReplyURL += "responsefile";
  1276. }
  1277. }
  1278. if ( TestResponseHeader( hRequest, HTTP_STRING( "BITS-Copy-File-To-Destination" ) ) )
  1279. {
  1280. BITSRenameFile( m_CacheFileDirectoryAndFile,
  1281. m_PhysicalPathAndFile );
  1282. }
  1283. InternetCloseHandle( hRequest );
  1284. InternetCloseHandle( hConnect );
  1285. InternetCloseHandle( hInternet );
  1286. hRequest = hInternet = hConnect = NULL;
  1287. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1288. CloseHandle( hResponseFile );
  1289. hResponseFile = INVALID_HANDLE_VALUE;
  1290. if ( ReplyURL.Size() )
  1291. {
  1292. Log( LOG_INFO, "The backend supplied a response url, send client response including URL" );
  1293. if ( 200 != dwStatus )
  1294. {
  1295. SendResponse(
  1296. "Pragma: no-cache\r\n"
  1297. "BITS-Packet-Type: Ack\r\n"
  1298. "Content-Length: 0\r\n"
  1299. "BITS-Received-Content-Range: %I64u\r\n"
  1300. "BITS-Reply-URL: %s\r\n"
  1301. "BITS-Error-Context: 0x7\r\n"
  1302. "\r\n",
  1303. dwStatus,
  1304. CacheFileSize,
  1305. (const char*)ReplyURL );
  1306. }
  1307. else
  1308. {
  1309. SendResponse(
  1310. "Pragma: no-cache\r\n"
  1311. "BITS-Packet-Type: Ack\r\n"
  1312. "Content-Length: 0\r\n"
  1313. "BITS-Received-Content-Range: %I64u\r\n"
  1314. "BITS-Reply-URL: %s\r\n"
  1315. "\r\n",
  1316. dwStatus,
  1317. CacheFileSize,
  1318. (const char*)ReplyURL );
  1319. }
  1320. }
  1321. else
  1322. {
  1323. Log( LOG_INFO, "The backend didn't supply a response URL, sending simple client response" );
  1324. if ( 200 != dwStatus )
  1325. {
  1326. SendResponse(
  1327. "Pragma: no-cache\r\n"
  1328. "BITS-Packet-Type: Ack\r\n"
  1329. "Content-Length: 0\r\n"
  1330. "BITS-Received-Content-Range: %I64u\r\n"
  1331. "BITS-Error-Context: 0x7\r\n"
  1332. "\r\n",
  1333. dwStatus,
  1334. CacheFileSize );
  1335. }
  1336. else
  1337. {
  1338. SendResponse(
  1339. "Pragma: no-cache\r\n"
  1340. "BITS-Packet-Type: Ack\r\n"
  1341. "Content-Length: 0\r\n"
  1342. "BITS-Received-Content-Range: %I64u\r\n"
  1343. "\r\n",
  1344. dwStatus,
  1345. CacheFileSize );
  1346. }
  1347. }
  1348. }
  1349. catch( ServerException Exception )
  1350. {
  1351. // cleanup
  1352. if ( INVALID_HANDLE_VALUE != hResponseFile )
  1353. {
  1354. CloseHandle( hResponseFile );
  1355. hResponseFile = INVALID_HANDLE_VALUE;
  1356. }
  1357. DeleteFile( m_ResponseFileDirectoryAndFile );
  1358. if ( hRequest )
  1359. InternetCloseHandle( hRequest );
  1360. if ( hConnect )
  1361. InternetCloseHandle( hConnect );
  1362. if ( hInternet )
  1363. InternetCloseHandle( hInternet );
  1364. throw;
  1365. }
  1366. }
  1367. bool
  1368. ServerRequest::TestResponseHeader(
  1369. HINTERNET hRequest,
  1370. const HTTP_STRING_TYPE *Header )
  1371. {
  1372. // test for a header in the notification response. If the header is
  1373. // found return true, false if not. Throw an exception on an error.
  1374. #if defined( USE_WININET )
  1375. SIZE_T HeaderSize = strlen(Header) + 2;
  1376. WorkStringBufferA WorkStringBufferData( HeaderSize );
  1377. char *HeaderDup = WorkStringBufferData.GetBuffer();
  1378. memcpy( HeaderDup, Header, ( HeaderSize - 1 ) * sizeof( char ) );
  1379. #else
  1380. SIZE_T HeaderSize = wcslen(Header) + 2;
  1381. WorkStringBufferW WorkStringBufferData( HeaderSize );
  1382. HTTP_STRING_TYPE *HeaderDup = ( HTTP_STRING_TYPE * )WorkStringBufferData.GetBuffer();
  1383. memcpy( HeaderDup, Header, ( HeaderSize - 1 ) * sizeof( WCHAR ) );
  1384. #endif
  1385. DWORD BufferLength = (DWORD)HeaderSize;
  1386. BOOL Result =
  1387. HttpQueryInfo(
  1388. hRequest,
  1389. HTTP_QUERY_CUSTOM,
  1390. HeaderDup,
  1391. &BufferLength,
  1392. NULL );
  1393. if ( Result )
  1394. return true;
  1395. DWORD dwLastError = GetLastError();
  1396. if ( ERROR_INSUFFICIENT_BUFFER == dwLastError )
  1397. return true;
  1398. if ( ERROR_HTTP_HEADER_NOT_FOUND == dwLastError )
  1399. return false;
  1400. Log( LOG_ERROR, "Unable to test response header %s, error %x",
  1401. (const char*) StringHandle( Header ), HRESULT_FROM_WIN32( GetLastError() ) );
  1402. throw ServerException( HRESULT_FROM_WIN32( dwLastError ) );
  1403. }
  1404. StringHandle
  1405. ServerRequest::GetResponseHeader(
  1406. HINTERNET hRequest,
  1407. const HTTP_STRING_TYPE *Header )
  1408. {
  1409. // Retrieve a header from a notification response. If the header is not
  1410. // found or an other error occures, throw an exception.
  1411. #if defined( USE_WININET )
  1412. SIZE_T HeaderSize = strlen( Header );
  1413. DWORD BufferLength = (DWORD)( ( HeaderSize + 1024 ) & ~( 1024 - 1 ) );
  1414. #else
  1415. SIZE_T HeaderSize = wcslen( Header );
  1416. DWORD BufferLength = (DWORD)( ( HeaderSize + 1024 ) & ~( 1024 - 1 ) );
  1417. #endif
  1418. HTTPStackStringHandle RetVal;
  1419. while(1)
  1420. {
  1421. HTTP_STRING_TYPE *Buffer = RetVal.AllocBuffer( BufferLength );
  1422. #if defined( USE_WININET )
  1423. memcpy( Buffer, Header, ( HeaderSize + 1 ) * sizeof( char ) );
  1424. #else
  1425. memcpy( Buffer, Header, ( HeaderSize + 1 ) * sizeof( WCHAR ) );
  1426. #endif
  1427. BOOL Result =
  1428. HttpQueryInfo(
  1429. hRequest,
  1430. HTTP_QUERY_CUSTOM,
  1431. Buffer,
  1432. &BufferLength,
  1433. NULL );
  1434. if ( Result )
  1435. {
  1436. RetVal.SetStringSize();
  1437. return StringHandle( RetVal );
  1438. }
  1439. DWORD dwError = GetLastError();
  1440. if ( ERROR_INSUFFICIENT_BUFFER != dwError )
  1441. {
  1442. Log( LOG_ERROR, "Unable to get response header %s, error %x",
  1443. ( const char *) StringHandle( Header ), HRESULT_FROM_WIN32( GetLastError() ) );
  1444. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  1445. }
  1446. RetVal = HTTPStackStringHandle();
  1447. }
  1448. }
  1449. void
  1450. ServerRequest::CloseSession()
  1451. {
  1452. // Handles the Close-Session command from the client.
  1453. CrackSessionId();
  1454. CrackPhysicalPath();
  1455. if ( BITS_NOTIFICATION_TYPE_NONE == m_DirectoryConfig->m_NotificationType )
  1456. {
  1457. BITSRenameFile( m_CacheFileDirectoryAndFile,
  1458. m_PhysicalPathAndFile );
  1459. }
  1460. else
  1461. {
  1462. BITSDeleteFile( m_CacheFileDirectoryAndFile );
  1463. }
  1464. BITSDeleteFile( m_ResponseFileDirectoryAndFile );
  1465. RemoveDirectory( m_ConnectionDirectory );
  1466. RemoveDirectory( m_ConnectionsDirectory );
  1467. SendResponse(
  1468. "Pragma: no-cache\r\n"
  1469. "BITS-Packet-Type: Ack\r\n"
  1470. "Content-Length: 0\r\n"
  1471. "\r\n" );
  1472. LogSessionClose( m_SessionId );
  1473. }
  1474. void
  1475. ServerRequest::CancelSession()
  1476. {
  1477. // Handles the Cancel-Session command from the client. Deletes
  1478. // all the temporary files, of the current state.
  1479. CrackSessionId();
  1480. CrackPhysicalPath();
  1481. BITSDeleteFile( m_CacheFileDirectoryAndFile );
  1482. BITSDeleteFile( m_ResponseFileDirectoryAndFile );
  1483. RemoveDirectory( m_ConnectionDirectory );
  1484. RemoveDirectory( m_ConnectionsDirectory );
  1485. SendResponse(
  1486. "Pragma: no-cache\r\n"
  1487. "BITS-Packet-Type: Ack\r\n"
  1488. "Content-Length: 0\r\n"
  1489. "\r\n" );
  1490. LogSessionCancel( m_SessionId );
  1491. }
  1492. void
  1493. ServerRequest::Ping()
  1494. {
  1495. // Handles the Ping command which is essentually just a no-op.
  1496. SendResponse(
  1497. "Pragma: no-cache\r\n"
  1498. "BITS-Packet-Type: Ack\r\n"
  1499. "Content-Length: 0\r\n"
  1500. "\r\n" );
  1501. }
  1502. void
  1503. ServerRequest::CrackPhysicalPath()
  1504. {
  1505. // Given a physical path, compute the destination cache directory and filename.
  1506. // The physical path is a directory, use the original name from the client.
  1507. const CHAR *PathTranslated = m_ExtensionControlBlock->lpszPathTranslated;
  1508. // perform some basic tests on the file name
  1509. StringHandle NewPathTranslated;
  1510. DWORD Attributes =
  1511. GetFileAttributes( m_ExtensionControlBlock->lpszPathTranslated );
  1512. if ( (DWORD)INVALID_FILE_ATTRIBUTES == Attributes )
  1513. {
  1514. if ( GetLastError() != ERROR_FILE_NOT_FOUND )
  1515. {
  1516. Log( LOG_ERROR, "Unable to get the file attributes for %s, error 0x%8.8X",
  1517. m_ExtensionControlBlock->lpszPathTranslated, HRESULT_FROM_WIN32( GetLastError() ) );
  1518. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1519. }
  1520. }
  1521. else
  1522. {
  1523. // file exists, check if its a directory
  1524. if ( FILE_ATTRIBUTE_DIRECTORY & Attributes )
  1525. {
  1526. Log( LOG_ERROR, "Uploading to directories are not supported" );
  1527. throw ServerException( E_INVALIDARG );
  1528. }
  1529. }
  1530. DWORD Result =
  1531. GetFullPathNameA(
  1532. PathTranslated,
  1533. 0,
  1534. NULL,
  1535. NULL );
  1536. if ( !Result )
  1537. {
  1538. Log( LOG_ERROR, "Unable to get full path name for %s, error 0x%8.8X",
  1539. m_ExtensionControlBlock->lpszPathTranslated, HRESULT_FROM_WIN32( GetLastError() ) );
  1540. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1541. }
  1542. DWORD RequiredBufferSize = Result;
  1543. WorkStringBuffer WorkCrackBuffer( RequiredBufferSize + 1 );
  1544. char *CrackBuffer = WorkCrackBuffer.GetBuffer();
  1545. char *FilePart = NULL;
  1546. Result =
  1547. GetFullPathNameA(
  1548. PathTranslated,
  1549. RequiredBufferSize,
  1550. CrackBuffer,
  1551. &FilePart );
  1552. if ( !Result )
  1553. {
  1554. DWORD Error = GetLastError();
  1555. Log( LOG_ERROR, "Unable to get full path name for %s, error 0x%8.8X",
  1556. m_ExtensionControlBlock->lpszPathTranslated, HRESULT_FROM_WIN32( Error ) );
  1557. throw ServerException( HRESULT_FROM_WIN32( Error ) );
  1558. }
  1559. if ( Result > RequiredBufferSize )
  1560. {
  1561. Log( LOG_ERROR, "Unable to get full path name for %s since the required buffer size changed.",
  1562. m_ExtensionControlBlock->lpszPathTranslated );
  1563. throw ServerException( E_OUTOFMEMORY );
  1564. }
  1565. if ( !FilePart ||
  1566. *FilePart == '\0' ||
  1567. FilePart == CrackBuffer )
  1568. {
  1569. Log( LOG_ERROR, "Request for %s is invalid since it doesn't contain both a file and a directory.",
  1570. m_ExtensionControlBlock->lpszPathTranslated );
  1571. throw ServerException( E_INVALIDARG );
  1572. }
  1573. // validate that the physical path is below the virtual directory root
  1574. {
  1575. SIZE_T VDirPathSize = m_DirectoryConfig->m_PhysicalPath.Size();
  1576. if ( _strnicmp( m_DirectoryConfig->m_PhysicalPath, CrackBuffer, VDirPathSize ) != 0 )
  1577. {
  1578. Log( LOG_ERROR, "Path is not below the virtual directory root, error" );
  1579. throw ServerException( E_INVALIDARG );
  1580. }
  1581. }
  1582. m_PhysicalPathAndFile = CrackBuffer;
  1583. m_PhysicalFile = FilePart;
  1584. *FilePart = '\0';
  1585. m_PhysicalPath = CrackBuffer;
  1586. m_ConnectionsDirectory = m_PhysicalPath + m_DirectoryConfig->m_ConnectionsDir + "\\";
  1587. m_ConnectionDirectory = m_ConnectionsDirectory + m_SessionIdString + "\\";
  1588. m_CacheFileDirectoryAndFile = m_ConnectionDirectory + "requestfile";
  1589. m_ResponseFileDirectoryAndFile = m_ConnectionDirectory + "responsefile";
  1590. }
  1591. void
  1592. ServerRequest::OpenCacheFile( )
  1593. {
  1594. // Open the cache file.
  1595. m_CacheFile =
  1596. CreateFile(
  1597. m_CacheFileDirectoryAndFile,
  1598. GENERIC_READ | GENERIC_WRITE,
  1599. 0,
  1600. NULL,
  1601. OPEN_ALWAYS,
  1602. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  1603. NULL );
  1604. if ( INVALID_HANDLE_VALUE == m_CacheFile )
  1605. {
  1606. Log( LOG_ERROR, "Unable to open cache file %s, error 0x%8.8X",
  1607. (const char*)m_CacheFileDirectoryAndFile,
  1608. HRESULT_FROM_WIN32( GetLastError() ) );
  1609. if (GetLastError() == ERROR_PATH_NOT_FOUND)
  1610. {
  1611. throw ServerException( BG_E_SESSION_NOT_FOUND );
  1612. }
  1613. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1614. }
  1615. }
  1616. void
  1617. ServerRequest::ReopenCacheFileAsSync()
  1618. {
  1619. // reopen the cache file as async so that it can be spooled synchronously over
  1620. // to the backend.
  1621. CloseCacheFile();
  1622. m_CacheFile =
  1623. CreateFile(
  1624. m_CacheFileDirectoryAndFile,
  1625. GENERIC_READ | GENERIC_WRITE,
  1626. 0,
  1627. NULL,
  1628. OPEN_ALWAYS,
  1629. FILE_ATTRIBUTE_NORMAL,
  1630. NULL );
  1631. if ( INVALID_HANDLE_VALUE == m_CacheFile )
  1632. {
  1633. Log( LOG_ERROR, "Unable to reopen cache file %s, error 0x%8.8X",
  1634. (const char*)m_CacheFileDirectoryAndFile,
  1635. HRESULT_FROM_WIN32( GetLastError() ) );
  1636. if (GetLastError() == ERROR_PATH_NOT_FOUND)
  1637. {
  1638. throw ServerException( BG_E_SESSION_NOT_FOUND );
  1639. }
  1640. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1641. }
  1642. }
  1643. void
  1644. ServerRequest::CloseCacheFile()
  1645. {
  1646. // Close the cache file, if it isn't already closed.
  1647. if ( INVALID_HANDLE_VALUE != m_CacheFile )
  1648. {
  1649. if ( CloseHandle( m_CacheFile ) )
  1650. m_CacheFile = INVALID_HANDLE_VALUE;
  1651. }
  1652. }
  1653. void
  1654. ServerRequest::ForwardComplete(
  1655. LPEXTENSION_CONTROL_BLOCK lpECB,
  1656. PVOID pContext,
  1657. DWORD cbIO,
  1658. DWORD dwError)
  1659. {
  1660. // A do nothing callback for forwarding the request.
  1661. ServerRequest *This = (ServerRequest*)pContext;
  1662. This->Release( );
  1663. }
  1664. void
  1665. ServerRequest::ForwardToNextISAPI()
  1666. {
  1667. // IIS6 has changed behavior where the limit on * entries are ignored.
  1668. // To work around this problem, it is necessary to send the request back
  1669. // to IIS.
  1670. BOOL Result;
  1671. Result =
  1672. (*m_ExtensionControlBlock->ServerSupportFunction)(
  1673. m_ExtensionControlBlock->ConnID,
  1674. HSE_REQ_IO_COMPLETION,
  1675. (LPVOID)ForwardComplete,
  1676. 0,
  1677. (LPDWORD)this );
  1678. if ( !Result )
  1679. {
  1680. Log( LOG_ERROR, "Unable to set callback to ForwardComplete, error %x",
  1681. HRESULT_FROM_WIN32( GetLastError() ) );
  1682. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1683. }
  1684. HSE_EXEC_URL_INFO ExecInfo;
  1685. memset( &ExecInfo, 0, sizeof( ExecInfo ) );
  1686. #define HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR 0x04
  1687. ExecInfo.dwExecUrlFlags = HSE_EXEC_URL_IGNORE_CURRENT_INTERCEPTOR;
  1688. ScheduleAsyncOperation(
  1689. HSE_REQ_EXEC_URL,
  1690. (LPVOID)&ExecInfo,
  1691. NULL,
  1692. NULL );
  1693. return;
  1694. }
  1695. void
  1696. ServerRequest::GetConfig()
  1697. {
  1698. // Looks up the configuration to use for this request.
  1699. StringHandle InstanceMetaPath = GetServerVariable( "INSTANCE_META_PATH" );
  1700. StringHandle URL = GetServerVariable( "URL" );
  1701. m_DirectoryConfig = g_ConfigMan->GetConfig( InstanceMetaPath, URL );
  1702. }
  1703. void
  1704. ServerRequest::DispatchRequest()
  1705. {
  1706. //
  1707. // The main do it function, parse what kind of request the client is sending and
  1708. // dispatch it to the appropiate handler routines.
  1709. //
  1710. // This critical section is needed because IIS callbacks can happen on any time.
  1711. // The lock is needed to prevent a callback from happening while the dispatch
  1712. // routine is still running.
  1713. CriticalSectionLock CSLock( &m_cs );
  1714. try
  1715. {
  1716. if ( _stricmp( m_ExtensionControlBlock->lpszMethod, BITS_COMMAND_VERBA ) != 0 )
  1717. {
  1718. Log( LOG_CALLBEGIN, "Connection %p, Packet-Type: %s, Method: %s, Path %s",
  1719. m_ExtensionControlBlock->ConnID,
  1720. (const char*)"UNKNOWN",
  1721. m_ExtensionControlBlock->lpszMethod,
  1722. m_ExtensionControlBlock->lpszPathTranslated );
  1723. ForwardToNextISAPI();
  1724. return;
  1725. }
  1726. m_PacketType = GetServerVariable( "HTTP_BITS-PACKET-TYPE" );
  1727. Log( LOG_CALLBEGIN, "Connection %p, Packet-Type: %s, Method: %s, Path %s",
  1728. m_ExtensionControlBlock->ConnID,
  1729. (const char*)m_PacketType,
  1730. m_ExtensionControlBlock->lpszMethod,
  1731. m_ExtensionControlBlock->lpszPathTranslated );
  1732. GetConfig();
  1733. if ( !m_DirectoryConfig->m_UploadEnabled )
  1734. {
  1735. Log( LOG_ERROR, "BITS uploads are not enabled" );
  1736. throw ServerException( E_ACCESSDENIED, 501 );
  1737. }
  1738. if ( m_DirectoryConfig->m_ExecutePermissions & ( MD_ACCESS_EXECUTE | MD_ACCESS_SCRIPT ) )
  1739. {
  1740. Log( LOG_ERROR, "BITS uploads are disable because execute or script access is enabled" );
  1741. LogExecuteEnabled();
  1742. throw ServerException( E_ACCESSDENIED, 403 );
  1743. }
  1744. StringHandle ContentLength = GetServerVariable( "HTTP_Content-Length" );
  1745. if ( 1 != sscanf( (const char*)ContentLength, "%I64u", &m_ContentLength ) )
  1746. {
  1747. Log( LOG_ERROR, "The content length is broken" );
  1748. throw ServerException( E_INVALIDARG );
  1749. }
  1750. if ( m_ContentLength < m_ExtensionControlBlock->cbAvailable )
  1751. throw ServerException( E_INVALIDARG );
  1752. m_BytesToDrain = m_ContentLength - m_ExtensionControlBlock->cbAvailable;
  1753. //
  1754. // Dispatch to the correct method
  1755. //
  1756. // Create-session
  1757. // fragment
  1758. // Get-Reply-Url
  1759. // Close-Session
  1760. // Cancel-Session
  1761. // Ping ( Is server alive )
  1762. // keep this list ordered by frequency
  1763. if ( _stricmp( m_PacketType, PACKET_TYPE_FRAGMENT ) == 0 )
  1764. AddFragment();
  1765. else if ( _stricmp( m_PacketType, PACKET_TYPE_PING ) == 0 )
  1766. Ping();
  1767. else if ( _stricmp( m_PacketType, PACKET_TYPE_CREATE_SESSION ) == 0 )
  1768. CreateSession();
  1769. else if ( _stricmp( m_PacketType, PACKET_TYPE_CLOSE_SESSION ) == 0 )
  1770. CloseSession();
  1771. else if ( _stricmp( m_PacketType, PACKET_TYPE_CANCEL_SESSION ) == 0 )
  1772. CancelSession();
  1773. else
  1774. {
  1775. Log( LOG_ERROR, "Received unknown BITS packet type %s",
  1776. (const char*)m_PacketType );
  1777. throw ServerException( E_INVALIDARG );
  1778. }
  1779. }
  1780. catch( ServerException Exception )
  1781. {
  1782. SendResponse( Exception );
  1783. }
  1784. }
  1785. //
  1786. // IIS Logger functions
  1787. //
  1788. void IISLogger::LogString( const char *String, int Size )
  1789. {
  1790. DWORD StringSize = Size + 1;
  1791. (*m_ExtensionControlBlock->ServerSupportFunction)
  1792. (
  1793. m_ExtensionControlBlock->ConnID,
  1794. HSE_APPEND_LOG_PARAMETER,
  1795. (LPVOID)String,
  1796. &StringSize,
  1797. NULL
  1798. );
  1799. }
  1800. void IISLogger::LogError( ServerException Error )
  1801. {
  1802. char OutputStr[ 255 ];
  1803. StringCbPrintfA(
  1804. OutputStr,
  1805. sizeof( OutputStr ),
  1806. "(bits_error:,%u,0x%8.8X)",
  1807. Error.GetHttpCode(),
  1808. Error.GetCode() );
  1809. LogString( OutputStr, strlen( OutputStr ) );
  1810. }
  1811. void IISLogger::LogError( const GUID & SessionID, ServerException Error )
  1812. {
  1813. WCHAR GuidStr[ 50 ];
  1814. char OutputStr[ 255 ];
  1815. StringFromGUID2( SessionID, GuidStr, 50 );
  1816. StringCchPrintfA(
  1817. OutputStr,
  1818. sizeof( OutputStr ),
  1819. "(bits_error:%S,%u,0x%8.8X)",
  1820. GuidStr,
  1821. Error.GetHttpCode(),
  1822. Error.GetCode() );
  1823. LogString( OutputStr, strlen( OutputStr ) );
  1824. }
  1825. void IISLogger::LogNewSession( const GUID & SessionID )
  1826. {
  1827. WCHAR GuidStr[ 50 ];
  1828. char OutputStr[ 255 ];
  1829. StringFromGUID2( SessionID, GuidStr, 50 );
  1830. StringCbPrintfA(
  1831. OutputStr,
  1832. sizeof( OutputStr ),
  1833. "(bits_new_session:%S)",
  1834. GuidStr );
  1835. LogString( OutputStr, strlen( OutputStr ) );
  1836. }
  1837. void IISLogger::LogUploadComplete( const GUID & SessionID, UINT64 FileSize )
  1838. {
  1839. WCHAR GuidStr[ 50 ];
  1840. char OutputStr[ 255 ];
  1841. StringFromGUID2( SessionID, GuidStr, 50 );
  1842. StringCbPrintfA(
  1843. OutputStr,
  1844. sizeof( OutputStr ),
  1845. "(bits_upload_complete:%S,%I64u)",
  1846. GuidStr,
  1847. FileSize );
  1848. LogString( OutputStr, strlen( OutputStr ) );
  1849. }
  1850. void IISLogger::LogSessionClose( const GUID & SessionID )
  1851. {
  1852. WCHAR GuidStr[ 50 ];
  1853. char OutputStr[ 255 ];
  1854. StringFromGUID2( SessionID, GuidStr, 50 );
  1855. StringCbPrintfA(
  1856. OutputStr,
  1857. sizeof( OutputStr ),
  1858. "(bits_close_session:%S)",
  1859. GuidStr );
  1860. LogString( OutputStr, strlen( OutputStr ) );
  1861. }
  1862. void IISLogger::LogSessionCancel( const GUID & SessionID )
  1863. {
  1864. WCHAR GuidStr[ 50 ];
  1865. char OutputStr[ 255 ];
  1866. StringFromGUID2( SessionID, GuidStr, 50 );
  1867. StringCbPrintfA(
  1868. OutputStr,
  1869. sizeof( OutputStr ),
  1870. "(bits_cancel_session:%S)",
  1871. GuidStr );
  1872. LogString( OutputStr, strlen( OutputStr ) );
  1873. }
  1874. void IISLogger::LogExecuteEnabled()
  1875. {
  1876. char OutputStr[ 255 ];
  1877. StringCchPrintfA(
  1878. OutputStr,
  1879. sizeof( OutputStr ),
  1880. "(bits_execute_enabled)" );
  1881. LogString( OutputStr, strlen( OutputStr ) );
  1882. }
  1883. ServerRequest *g_LastRequest = NULL;
  1884. //
  1885. // AsyncReader functions
  1886. //
  1887. AsyncReader::AsyncReader(
  1888. ServerRequest *Request,
  1889. UINT64 BytesToDrain,
  1890. UINT64 BytesToWrite,
  1891. UINT64 WriteOffset,
  1892. bool IsLastBlock,
  1893. HANDLE WriteHandle,
  1894. char *PrereadBuffer,
  1895. DWORD PrereadSize ) :
  1896. m_Request( Request ),
  1897. m_BytesToDrain( BytesToDrain ),
  1898. m_BytesToWrite( BytesToWrite ),
  1899. m_WriteOffset( WriteOffset ),
  1900. m_ReadOffset( WriteOffset ),
  1901. m_IsLastBlock( IsLastBlock ),
  1902. m_WriteHandle( WriteHandle ),
  1903. m_BytesToRead( BytesToWrite ),
  1904. m_PrereadBuffer( PrereadBuffer ),
  1905. m_PrereadSize( PrereadSize ),
  1906. m_OperationsPending( 0 ),
  1907. m_ReadBuffer( 0 ),
  1908. m_WriteBuffer( 0 ),
  1909. m_BuffersToWrite( 0 ),
  1910. m_Error( S_OK ),
  1911. m_WritePending( false ),
  1912. m_ReadPending( false ),
  1913. m_TotalBytesRead( 0 ),
  1914. m_ThreadToken( NULL ),
  1915. m_ErrorValid( false )
  1916. {
  1917. #if defined CLEARASYNCBUFFERS
  1918. for ( int i = 0; i < NUMBER_OF_IO_BUFFERS; i++ )
  1919. {
  1920. memset( m_IOBuffers + i, i, sizeof( *m_IOBuffers ) );
  1921. }
  1922. #endif
  1923. if ( !OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &m_ThreadToken ) )
  1924. {
  1925. Log( LOG_ERROR, "Unable to retrieve the current thread token, error %x",
  1926. HRESULT_FROM_WIN32( GetLastError() ) );
  1927. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1928. }
  1929. if ( m_BytesToDrain && m_PrereadSize )
  1930. {
  1931. Log( LOG_INFO, "Have both a Preread and bytes to drain, deal with it." );
  1932. Log( LOG_INFO, "BytesToDrain: %I64u, PrereadSize: %u", m_BytesToDrain, m_PrereadSize );
  1933. DWORD DrainBytesInPreread = (DWORD)min( m_BytesToDrain, PrereadSize );
  1934. m_PrereadBuffer += DrainBytesInPreread;
  1935. m_PrereadSize -= DrainBytesInPreread;
  1936. m_BytesToDrain -= DrainBytesInPreread;
  1937. Log( LOG_INFO, "Bytes to drain from preread, %u", DrainBytesInPreread );
  1938. }
  1939. ASSERT( !( m_BytesToDrain && m_PrereadSize ) );
  1940. m_BytesToRead = m_BytesToRead + m_BytesToDrain - m_PrereadSize;
  1941. m_ReadOffset = m_ReadOffset - m_BytesToDrain + m_PrereadSize;
  1942. if ( m_BytesToRead )
  1943. {
  1944. // Setup the read completion callback
  1945. BOOL Result =
  1946. (*m_Request->m_ExtensionControlBlock->ServerSupportFunction)(
  1947. m_Request->m_ExtensionControlBlock->ConnID,
  1948. HSE_REQ_IO_COMPLETION,
  1949. (LPVOID)ReadCompleteWraper,
  1950. 0,
  1951. (LPDWORD)this );
  1952. if ( !Result )
  1953. {
  1954. Log( LOG_ERROR, "Unable to set callback to ReadCompleteWraper, error %x",
  1955. HRESULT_FROM_WIN32( GetLastError() ) );
  1956. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1957. }
  1958. }
  1959. if ( INVALID_HANDLE_VALUE != m_WriteHandle )
  1960. {
  1961. BOOL Result =
  1962. BindIoCompletionCallback(
  1963. m_WriteHandle, // handle to file
  1964. (LPOVERLAPPED_COMPLETION_ROUTINE)WriteCompleteWraper, // callback
  1965. 0 // reserved
  1966. );
  1967. if ( !Result )
  1968. {
  1969. Log( LOG_ERROR, "Unable to set write completion routing, error %x",
  1970. HRESULT_FROM_WIN32( GetLastError() ) );
  1971. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  1972. }
  1973. }
  1974. // Queue the IO to a thread pool work item.
  1975. BOOL bResult =
  1976. QueueUserWorkItem( StartupIOWraper, this, WT_EXECUTEDEFAULT );
  1977. if ( !bResult )
  1978. {
  1979. Log( LOG_ERROR, "QueueUserWorkItem failed, error %x",
  1980. HRESULT_FROM_WIN32( GetLastError() ) );
  1981. throw ServerException( 500, HRESULT_FROM_WIN32( GetLastError() ) );
  1982. }
  1983. m_OperationsPending++;
  1984. Request->m_IsPending = true;
  1985. Request->AddRef();
  1986. }
  1987. AsyncReader::~AsyncReader()
  1988. {
  1989. if ( m_ThreadToken )
  1990. CloseHandle( m_ThreadToken );
  1991. }
  1992. void
  1993. AsyncReader::HandleError( ServerException Error )
  1994. {
  1995. m_ErrorValid = true;
  1996. m_Error = Error;
  1997. if ( m_OperationsPending )
  1998. return; // Continue to wait for operations to exit.
  1999. m_Request->HandleIOError( this, Error, m_TotalBytesRead );
  2000. return;
  2001. }
  2002. void
  2003. AsyncReader::CompleteIO()
  2004. {
  2005. m_Request->CompleteIO( this, m_TotalBytesRead );
  2006. return;
  2007. }
  2008. void
  2009. AsyncReader::StartReadRequest()
  2010. {
  2011. // start a new IIS read request
  2012. DWORD BytesToRead;
  2013. IOBuffer *Buffer = m_IOBuffers + m_ReadBuffer;
  2014. if ( m_BytesToDrain )
  2015. {
  2016. Buffer->m_BufferWriteOffset = 0;
  2017. Buffer->m_BufferUsed = 0;
  2018. BytesToRead = (DWORD)min( m_BytesToDrain, sizeof( Buffer->m_Buffer ) );
  2019. }
  2020. else
  2021. {
  2022. Buffer->m_BufferWriteOffset = m_ReadOffset;
  2023. Buffer->m_BufferUsed = 0;
  2024. BytesToRead = (DWORD)min( m_BytesToRead, sizeof( Buffer->m_Buffer ) );
  2025. }
  2026. Log( LOG_INFO, "Start Async Read, Connection %p, Buffer %u, Offset %I64u, Length %u",
  2027. m_Request->m_ExtensionControlBlock->ConnID,
  2028. m_ReadBuffer,
  2029. m_ReadOffset,
  2030. BytesToRead );
  2031. DWORD Flags = HSE_IO_ASYNC;
  2032. BOOL Result =
  2033. (*m_Request->m_ExtensionControlBlock->ServerSupportFunction)
  2034. (
  2035. m_Request->m_ExtensionControlBlock->ConnID,
  2036. HSE_REQ_ASYNC_READ_CLIENT,
  2037. Buffer->m_Buffer,
  2038. &BytesToRead,
  2039. &Flags
  2040. );
  2041. if ( !Result )
  2042. {
  2043. DWORD Error = GetLastError();
  2044. Log( LOG_ERROR, "HSE_REQ_ASYNC_READ_CLIENT failed, error 0x%8.8", Error );
  2045. throw ServerException( HRESULT_FROM_WIN32( Error ) );
  2046. }
  2047. m_OperationsPending++;
  2048. m_ReadPending = true;
  2049. m_Request->AddRef();
  2050. }
  2051. void
  2052. AsyncReader::StartWriteRequest()
  2053. {
  2054. // Start a new filesystem write request
  2055. OVERLAPPED *OverLapped = (OVERLAPPED*)this;
  2056. memset( OverLapped, 0, sizeof(*OverLapped) );
  2057. LPCVOID WriteBuffer;
  2058. DWORD BytesToWrite;
  2059. if ( m_PrereadSize )
  2060. {
  2061. // IIS preread data is handled seperatly. Drain it first.
  2062. WriteBuffer = m_PrereadBuffer;
  2063. BytesToWrite = m_PrereadSize;
  2064. }
  2065. else
  2066. {
  2067. IOBuffer *Buffer = m_IOBuffers + m_WriteBuffer;
  2068. ASSERT( m_WriteOffset == Buffer->m_BufferWriteOffset );
  2069. WriteBuffer = Buffer->m_Buffer;
  2070. BytesToWrite = Buffer->m_BufferUsed;
  2071. }
  2072. OverLapped->Offset = (DWORD)(m_WriteOffset & 0xFFFFFFFF);
  2073. OverLapped->OffsetHigh = (DWORD)((m_WriteOffset >> 32) & 0xFFFFFFFF);
  2074. Log( LOG_INFO, "Start Async Write, Connection %p, Buffer %u, Offset %I64u, Length %u",
  2075. m_Request->m_ExtensionControlBlock->ConnID,
  2076. m_WriteBuffer,
  2077. m_WriteOffset,
  2078. BytesToWrite );
  2079. BOOL Result =
  2080. WriteFile(
  2081. m_WriteHandle,
  2082. WriteBuffer,
  2083. BytesToWrite,
  2084. NULL,
  2085. OverLapped );
  2086. if ( !Result && GetLastError() != ERROR_IO_PENDING )
  2087. {
  2088. DWORD Error = GetLastError();
  2089. Log( LOG_ERROR, "WriteFileEx failed, error 0x%8.8X", GetLastError() );
  2090. throw ServerException( HRESULT_FROM_WIN32( Error ) );
  2091. }
  2092. m_OperationsPending++;
  2093. m_WritePending = true;
  2094. m_Request->AddRef();
  2095. }
  2096. void
  2097. AsyncReader::StartupIO( )
  2098. {
  2099. // Startup the necessary IO operations based on the
  2100. // buffer states. returns true if the upload operation should continue.
  2101. try
  2102. {
  2103. if ( m_ErrorValid )
  2104. throw ServerException( m_Error );
  2105. bool ScheduledIO = false;
  2106. if ( m_BytesToDrain )
  2107. {
  2108. StartReadRequest();
  2109. ScheduledIO = true;
  2110. }
  2111. else
  2112. {
  2113. if ( !m_BytesToWrite && !m_BytesToDrain )
  2114. return CompleteIO();
  2115. if ( !m_WritePending )
  2116. {
  2117. if ( m_PrereadSize )
  2118. {
  2119. StartWriteRequest();
  2120. ScheduledIO = true;
  2121. }
  2122. else if ( m_BuffersToWrite )
  2123. {
  2124. StartWriteRequest();
  2125. ScheduledIO = true;
  2126. }
  2127. }
  2128. if ( !m_ReadPending && m_BytesToRead && ( NUMBER_OF_IO_BUFFERS - m_BuffersToWrite ) )
  2129. {
  2130. StartReadRequest();
  2131. ScheduledIO = true;
  2132. }
  2133. }
  2134. if ( !ScheduledIO )
  2135. Log( LOG_INFO, "No IO scheduled" );
  2136. }
  2137. catch( ServerException Error )
  2138. {
  2139. HandleError( Error );
  2140. }
  2141. return;
  2142. }
  2143. void
  2144. AsyncReader::WriteComplete( DWORD dwError, DWORD BytesWritten )
  2145. {
  2146. // Called when a write is completed. Determine the next buffer to use and startup the correct IO operations.
  2147. // returns true is more operations are necessary.
  2148. try
  2149. {
  2150. Log( LOG_INFO, "Complete Async Write, Connection %p, Buffer %u, Offset %I64u, Length %u, Error %u",
  2151. m_Request->m_ExtensionControlBlock->ConnID,
  2152. m_WriteBuffer,
  2153. m_WriteOffset,
  2154. BytesWritten,
  2155. dwError );
  2156. if ( m_ErrorValid )
  2157. throw ServerException( m_Error );
  2158. m_WritePending = false;
  2159. if ( dwError )
  2160. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  2161. m_BytesToWrite -= BytesWritten;
  2162. if ( m_PrereadSize )
  2163. {
  2164. m_PrereadSize -= BytesWritten;
  2165. m_PrereadBuffer += BytesWritten;
  2166. m_WriteOffset += BytesWritten;
  2167. }
  2168. else
  2169. {
  2170. IOBuffer *Buffer = m_IOBuffers + m_WriteBuffer;
  2171. ASSERT( BytesWritten == Buffer->m_BufferUsed );
  2172. m_WriteOffset += Buffer->m_BufferUsed;
  2173. m_BuffersToWrite--;
  2174. #if defined CLEARASYNCBUFFERS
  2175. memset( Buffer, m_WriteBuffer, sizeof(*Buffer) );
  2176. #endif
  2177. m_WriteBuffer = (m_WriteBuffer + 1 ) % NUMBER_OF_IO_BUFFERS;
  2178. }
  2179. return StartupIO();
  2180. }
  2181. catch( ServerException Error )
  2182. {
  2183. Log( LOG_ERROR, "Error in write complete" );
  2184. HandleError( Error );
  2185. }
  2186. }
  2187. void
  2188. AsyncReader::ReadComplete( DWORD dwError, DWORD BytesRead )
  2189. {
  2190. // Called when a read operation is complete. determines if more operations should start or to
  2191. // complete the operation.
  2192. // returns true if more operations are operations are needed to complete the upload
  2193. try
  2194. {
  2195. Log( LOG_INFO, "Complete Async Read, Connection %p, Buffer %u, Offset %I64u, Length %u, Error %u",
  2196. m_Request->m_ExtensionControlBlock->ConnID,
  2197. m_ReadBuffer,
  2198. m_ReadOffset,
  2199. BytesRead,
  2200. dwError );
  2201. m_TotalBytesRead += BytesRead;
  2202. if ( m_ErrorValid )
  2203. throw ServerException( m_Error );
  2204. m_ReadPending = false;
  2205. if ( dwError )
  2206. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  2207. IOBuffer *Buffer = m_IOBuffers + m_ReadBuffer;
  2208. Buffer->m_BufferUsed = BytesRead;
  2209. m_BytesToRead -= BytesRead;
  2210. m_ReadOffset += BytesRead;
  2211. bool ScheduledIO = false;
  2212. if ( m_BytesToDrain )
  2213. m_BytesToDrain -= BytesRead;
  2214. else
  2215. {
  2216. m_BuffersToWrite++;
  2217. m_ReadBuffer = (m_ReadBuffer + 1 ) % NUMBER_OF_IO_BUFFERS;
  2218. }
  2219. StartupIO(); // Continue IO
  2220. }
  2221. catch( ServerException Error )
  2222. {
  2223. Log( LOG_ERROR, "Error in read complete" );
  2224. HandleError( Error );
  2225. }
  2226. }
  2227. DWORD
  2228. AsyncReader::StartupIOWraper( LPVOID Context )
  2229. {
  2230. AsyncReader *Reader = (AsyncReader*)Context;
  2231. {
  2232. CriticalSectionLock CSLock( &Reader->m_Request->m_cs );
  2233. Reader->m_OperationsPending--;
  2234. // Thread pool threads should start and end with no token
  2235. BITSSetCurrentThreadToken( Reader->m_ThreadToken );
  2236. Reader->StartupIO();
  2237. }
  2238. Reader->m_Request->Release();
  2239. // revert to previous impersonation.
  2240. BITSSetCurrentThreadToken( NULL );
  2241. return 0;
  2242. }
  2243. void CALLBACK
  2244. AsyncReader::WriteCompleteWraper(
  2245. DWORD dwErrorCode,
  2246. DWORD dwNumberOfBytesTransfered,
  2247. LPOVERLAPPED lpOverlapped )
  2248. {
  2249. // Wrapper around write completions
  2250. Log( LOG_INFO, "WriteCompleteWraper begin" );
  2251. AsyncReader *Reader = (AsyncReader*)lpOverlapped;
  2252. {
  2253. CriticalSectionLock CSLock( &Reader->m_Request->m_cs );
  2254. Reader->m_OperationsPending--;
  2255. // Thread pool threads should start and end with no token
  2256. BITSSetCurrentThreadToken( Reader->m_ThreadToken );
  2257. Reader->WriteComplete( dwErrorCode, dwNumberOfBytesTransfered );
  2258. }
  2259. Reader->m_Request->Release();
  2260. // revert to previous security
  2261. BITSSetCurrentThreadToken( NULL );
  2262. }
  2263. void WINAPI
  2264. AsyncReader::ReadCompleteWraper(
  2265. LPEXTENSION_CONTROL_BLOCK,
  2266. PVOID pContext,
  2267. DWORD cbIO,
  2268. DWORD dwError )
  2269. {
  2270. // wrapper around read completions
  2271. Log( LOG_INFO, "ReadCompleteWraper begin" );
  2272. AsyncReader *Reader = (AsyncReader*)pContext;
  2273. {
  2274. CriticalSectionLock CSLock( &Reader->m_Request->m_cs );
  2275. Reader->m_OperationsPending--;
  2276. #if defined( DBG )
  2277. {
  2278. HANDLE ThreadToken = NULL;
  2279. ASSERT( OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &ThreadToken ) );
  2280. if ( ThreadToken )
  2281. CloseHandle( ThreadToken );
  2282. }
  2283. #endif
  2284. Reader->ReadComplete( dwError, cbIO );
  2285. }
  2286. Reader->m_Request->Release();
  2287. }
  2288. bool g_ExtensionRunning = false;
  2289. class ConfigurationManager *g_ConfigMan = NULL;
  2290. class PropertyIDManager *g_PropertyMan = NULL;
  2291. BOOL WINAPI
  2292. GetExtensionVersion(
  2293. OUT HSE_VERSION_INFO * pVer
  2294. )
  2295. {
  2296. // IIS calls this to start everything up.
  2297. HRESULT Hr = S_OK;
  2298. ASSERT( !g_ExtensionRunning );
  2299. pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
  2300. HSE_VERSION_MAJOR );
  2301. StringCbCopyA(
  2302. pVer->lpszExtensionDesc,
  2303. sizeof( pVer->lpszExtensionDesc ),
  2304. "BITS Server Extensions" );
  2305. if ( g_ExtensionRunning )
  2306. return true;
  2307. Hr = LogInit();
  2308. if ( FAILED( Hr ) )
  2309. {
  2310. SetLastError( Hr );
  2311. return false;
  2312. }
  2313. Log( LOG_INFO, "GetExtensionVersion called, starting init" );
  2314. try
  2315. {
  2316. Log( LOG_INFO, "Initializing Property Manager..." );
  2317. g_PropertyMan = new PropertyIDManager();
  2318. HRESULT Hr2 =
  2319. g_PropertyMan->LoadPropertyInfo();
  2320. if ( FAILED(Hr2) )
  2321. throw ServerException( Hr2 );
  2322. Log( LOG_INFO, "Initializing Configuration Manager..." );
  2323. g_ConfigMan = new ConfigurationManager();
  2324. }
  2325. catch( ServerException Exception )
  2326. {
  2327. Log( LOG_ERROR, "Error during initialization, 0x%8.8X", Exception.GetCode() );
  2328. delete g_ConfigMan;
  2329. delete g_PropertyMan;
  2330. LogClose();
  2331. SetLastError( Exception.GetCode() );
  2332. return false;
  2333. }
  2334. g_ExtensionRunning = true;
  2335. Log( LOG_INFO, "Initialization complete!" );
  2336. return true;
  2337. }
  2338. BOOL WINAPI
  2339. TerminateExtension(
  2340. IN DWORD dwFlags
  2341. )
  2342. {
  2343. //
  2344. // IIS calls this to shut everything down.
  2345. //
  2346. if ( !g_ExtensionRunning )
  2347. return true;
  2348. Log( LOG_INFO, "Shuting down config manager..." );
  2349. delete g_ConfigMan;
  2350. g_ConfigMan = NULL;
  2351. Log( LOG_INFO, "Shuting down property manager..." );
  2352. delete g_PropertyMan;
  2353. g_PropertyMan = NULL;
  2354. Log( LOG_INFO, "Closing logging, goodbye" );
  2355. LogClose();
  2356. g_ExtensionRunning = false;
  2357. return true;
  2358. }
  2359. DWORD WINAPI
  2360. HttpExtensionProc(
  2361. IN EXTENSION_CONTROL_BLOCK * pECB
  2362. )
  2363. {
  2364. //
  2365. // IIS calls this function for each request that is forwarded by the filter.
  2366. //
  2367. DWORD Result = HSE_STATUS_ERROR;
  2368. ServerRequest *Request = NULL;
  2369. try
  2370. {
  2371. g_LastRequest = Request = new ServerRequest( pECB );
  2372. Request->DispatchRequest();
  2373. Result = Request->IsPending() ? HSE_STATUS_PENDING : HSE_STATUS_SUCCESS;
  2374. }
  2375. catch( ServerException Exception )
  2376. {
  2377. IISLogger Logger( pECB );
  2378. Logger.LogError( Exception );
  2379. Result = HSE_STATUS_ERROR;
  2380. }
  2381. if ( Request )
  2382. Request->Release();
  2383. return Result;
  2384. }
  2385. HMODULE g_hinst;
  2386. BOOL WINAPI
  2387. DllMain(
  2388. IN HINSTANCE hinstDll,
  2389. IN DWORD dwReason,
  2390. IN LPVOID lpvContext
  2391. )
  2392. /*++
  2393. Function : DllMain
  2394. Description:
  2395. The initialization function for this DLL.
  2396. Arguments:
  2397. hinstDll - Instance handle of the DLL
  2398. dwReason - Reason why NT called this DLL
  2399. lpvContext - Reserved parameter for future use
  2400. Return Value:
  2401. Returns TRUE if successfull; otherwise FALSE.
  2402. --*/
  2403. {
  2404. // Note that appropriate initialization and termination code
  2405. // would be written within the switch statement below. Because
  2406. // this example is very simple, none is currently needed.
  2407. switch( dwReason ) {
  2408. case DLL_PROCESS_ATTACH:
  2409. g_hinst = hinstDll;
  2410. break;
  2411. case DLL_PROCESS_DETACH:
  2412. break;
  2413. }
  2414. return(TRUE);
  2415. }
  2416. #include "bitssrvcfgimp.h"