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.

411 lines
9.6 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. ssi_vector_send.cxx
  5. Abstract:
  6. wrapper for VectorSend related buffer manipulation
  7. Segments of final response of stm file processing
  8. are buffered in the SSI_VECTOR_BUFFER to optimize the
  9. "send response" path
  10. Author:
  11. Jaroslad Apr-2001
  12. --*/
  13. #include "precomp.hxx"
  14. HRESULT
  15. SSI_VECTOR_BUFFER::AddVectorHeaders(
  16. IN CHAR * pszHeaders,
  17. IN BOOL fIncludesContentLength,
  18. IN CHAR * pszStatus
  19. )
  20. /*++
  21. Routine Description:
  22. add headers and status line to be sent in response
  23. Note: caller is responsible to ensure that
  24. pszHeaders and pszStatus will not be freed
  25. If lifetime cannot be guaranteed or use AllocateSpace() to allocate memory
  26. Arguments:
  27. pszHeaders - pointer to headers (including \r\n)
  28. fIncludesContentLength - flag that headers include "Content-Length" header
  29. pszStatus - if "" then it will be filled in automatically to "200 OK"
  30. Return Value:
  31. HRESULT
  32. --*/
  33. {
  34. //
  35. // function is expected to be called not more than once per request
  36. //
  37. if ( !_fHeadersSent )
  38. {
  39. _RespVector.dwFlags |= HSE_IO_SEND_HEADERS;
  40. DBG_ASSERT( _RespVector.pszHeaders == NULL );
  41. _RespVector.pszHeaders = pszHeaders;
  42. _fVectorHeadersIncludeContentLength = fIncludesContentLength;
  43. //
  44. // pszStatus is required not to be NULL with HSE_IO_SEND_HEADERS
  45. // so set it to empty string
  46. //
  47. _RespVector.pszStatus = pszStatus;
  48. }
  49. else
  50. {
  51. DBG_ASSERT( FALSE );
  52. return( E_FAIL );
  53. }
  54. return S_OK;
  55. }
  56. HRESULT
  57. SSI_VECTOR_BUFFER::AddToVector(
  58. IN PCHAR pbData,
  59. IN DWORD cbData
  60. )
  61. /*++
  62. Routine Description:
  63. add another chunk to response Vector
  64. Note: caller is responsible to ensure that
  65. buffer will not be freed until VectorSend completed
  66. If lifetime cannot be guaranteed use CopyToVector()
  67. instead (or use AllocateSpace() to allocate memory
  68. for pbData )
  69. Arguments:
  70. pbData - pointer to chunk
  71. cbData - size of chunk
  72. Return Value:
  73. HRESULT
  74. --*/
  75. {
  76. DWORD nElementCount = _RespVector.nElementCount;
  77. if( cbData != 0 )
  78. {
  79. if (!_buffVectorElementArray.Resize( (nElementCount + 1)*sizeof(HSE_VECTOR_ELEMENT) , 256 ))
  80. {
  81. return HRESULT_FROM_WIN32(GetLastError());
  82. }
  83. _RespVector.lpElementArray = (HSE_VECTOR_ELEMENT *)_buffVectorElementArray.QueryPtr();
  84. _RespVector.lpElementArray[ nElementCount ].ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  85. _RespVector.lpElementArray[ nElementCount ].pvContext = pbData;
  86. _RespVector.lpElementArray[ nElementCount ].cbSize = cbData;
  87. _cbTotalBytesInVector += cbData;
  88. _RespVector.nElementCount++;
  89. }
  90. return S_OK;
  91. }
  92. HRESULT
  93. SSI_VECTOR_BUFFER::AddFileChunkToVector(
  94. IN DWORD cbOffset,
  95. IN DWORD cbData,
  96. IN HANDLE hFile
  97. )
  98. /*++
  99. Routine Description:
  100. add another chunk to response Vector
  101. Note: caller is responsible to ensure that
  102. buffer will nt be freed until VectorSend completed
  103. If lifetime cannot be guaranteed use CopyToVector()
  104. instead (or use AllocateSpace() to allocate memory
  105. for pbData )
  106. Arguments:
  107. pbOffset - offset within the file
  108. cbData - size of chunk
  109. hFile - file where file chunk is located
  110. Return Value:
  111. HRESULT
  112. --*/
  113. {
  114. DWORD nElementCount = _RespVector.nElementCount;
  115. if( cbData != 0 )
  116. {
  117. if (!_buffVectorElementArray.Resize( (nElementCount + 1)*sizeof(HSE_VECTOR_ELEMENT) , 256 ))
  118. {
  119. return HRESULT_FROM_WIN32(GetLastError());
  120. }
  121. _RespVector.lpElementArray = (HSE_VECTOR_ELEMENT *)_buffVectorElementArray.QueryPtr();
  122. _RespVector.lpElementArray[ nElementCount ].ElementType = HSE_VECTOR_ELEMENT_TYPE_FILE_HANDLE;
  123. _RespVector.lpElementArray[ nElementCount ].pvContext = hFile;
  124. _RespVector.lpElementArray[ nElementCount ].cbOffset = cbOffset;
  125. _RespVector.lpElementArray[ nElementCount ].cbSize = cbData;
  126. _cbTotalBytesInVector += cbData;
  127. _RespVector.nElementCount++;
  128. }
  129. return S_OK;
  130. }
  131. HRESULT
  132. SSI_VECTOR_BUFFER::CopyToVector(
  133. IN PCHAR pszData,
  134. IN DWORD cchData
  135. )
  136. /*++
  137. Routine Description:
  138. Copy data to private buffer and then add it
  139. to response Vector
  140. Arguments:
  141. pbData - pointer to chunk
  142. cbData - size of chunk
  143. Return Value:
  144. HRESULT
  145. --*/
  146. {
  147. PCHAR pszVectorBufferSpace = NULL;
  148. HRESULT hr = E_FAIL;
  149. //
  150. // Allocate space in private buffer
  151. //
  152. if ( FAILED( hr = AllocateSpace(
  153. cchData,
  154. &pszVectorBufferSpace
  155. ) ) )
  156. {
  157. return hr;
  158. }
  159. else
  160. {
  161. memcpy( pszVectorBufferSpace,
  162. pszData,
  163. cchData );
  164. hr = AddToVector( pszVectorBufferSpace,
  165. cchData );
  166. }
  167. return hr;
  168. }
  169. HRESULT
  170. SSI_VECTOR_BUFFER::CopyToVector(
  171. IN STRA& straSource
  172. )
  173. /*++
  174. Routine Description:
  175. Copy data to private buffer and then add it
  176. to response Vector
  177. Arguments:
  178. straSource -string to be copied
  179. Return Value:
  180. HRESULT
  181. --*/
  182. {
  183. return CopyToVector( straSource.QueryStr(),
  184. straSource.QueryCB() );
  185. }
  186. HRESULT
  187. SSI_VECTOR_BUFFER::CopyToVector(
  188. IN STRU& struSource
  189. )
  190. /*++
  191. Routine Description:
  192. Copy data to private buffer and then add it
  193. to response Vector
  194. Arguments:
  195. struSource - string to be copied
  196. Return Value:
  197. HRESULT
  198. --*/
  199. {
  200. HRESULT hr = E_FAIL;
  201. STRA straSource;
  202. if ( FAILED( hr = straSource.CopyW( struSource.QueryStr() ) ) )
  203. {
  204. return hr;
  205. }
  206. else
  207. {
  208. return CopyToVector( straSource );
  209. }
  210. }
  211. HRESULT
  212. SSI_VECTOR_BUFFER::VectorSend(
  213. OUT BOOL * pfAsyncPending,
  214. IN BOOL fFinalSend
  215. )
  216. /*++
  217. Routine Description:
  218. HSE_REQ_VECTOR_SEND wrapper.
  219. Arguments:
  220. pfAsyncPending - Set to TRUE if async is pending
  221. fFinalSend - TRUE if this is the last send for the response
  222. it can help to determine if Keep-alive can be used
  223. Return Value:
  224. HRESULT
  225. --*/
  226. {
  227. HRESULT hr = E_FAIL;
  228. DBG_ASSERT( pfAsyncPending != NULL );
  229. *pfAsyncPending = FALSE;
  230. //
  231. // check if there is any data to be sent
  232. //
  233. if ( ( _RespVector.pszHeaders == NULL &&
  234. _RespVector.nElementCount == 0 ) ||
  235. ( _fHeadersSent &&
  236. _fHeadRequest ) )
  237. {
  238. //
  239. // there is nothing to be sent
  240. // Also handle HEAD requests. Never send body with them
  241. // handling HEAD request by processing whole SSI and only not
  242. // sending data is not ideal, but this way it is guaranteed
  243. // that HEAD and GET will get same headers
  244. //
  245. *pfAsyncPending = FALSE;
  246. return S_OK;
  247. }
  248. if ( _fVectorHeadersIncludeContentLength )
  249. {
  250. //
  251. // remove the disconnect flag since we have content length
  252. //
  253. _RespVector.dwFlags &= ( ~HSE_IO_DISCONNECT_AFTER_SEND );
  254. }
  255. else if ( !_fHeadersSent
  256. && fFinalSend )
  257. {
  258. //
  259. // Optimization:
  260. // This is final send and headers were not yet sent
  261. // That means we can do keep-alive and specify Content-length
  262. //
  263. STACK_STRA( straFinalHeaders, SSI_DEFAULT_RESPONSE_HEADERS_SIZE + 1 );
  264. CHAR achNum[ SSI_MAX_NUMBER_STRING + 1 ];
  265. _ultoa( _cbTotalBytesInVector,
  266. achNum,
  267. 10 );
  268. if ( FAILED( hr = _straFinalHeaders.Copy( "Content-Length: " ) ) )
  269. {
  270. return hr;
  271. }
  272. if ( FAILED( hr = _straFinalHeaders.Append( achNum ) ) )
  273. {
  274. return hr;
  275. }
  276. if ( FAILED( hr = _straFinalHeaders.Append( "\r\n" ) ) )
  277. {
  278. return hr;
  279. }
  280. if ( FAILED( hr = _straFinalHeaders.Append( _RespVector.pszHeaders ) ) )
  281. {
  282. return hr;
  283. }
  284. _RespVector.pszHeaders = _straFinalHeaders.QueryStr();
  285. // remove the disconnect flag
  286. _RespVector.dwFlags &= ( ~HSE_IO_DISCONNECT_AFTER_SEND );
  287. }
  288. //
  289. // Send Response Vector
  290. //
  291. if( _RespVector.dwFlags & HSE_IO_SEND_HEADERS )
  292. {
  293. _fHeadersSent = TRUE;
  294. }
  295. if ( _fHeadRequest )
  296. {
  297. // Handle HEAD requests. Never send body with them
  298. // Handling HEAD request by processing the whole SSI and only not
  299. // sending data is not ideal, but this way it is guaranteed
  300. // that HEAD and GET will get the same headers
  301. //
  302. _RespVector.nElementCount = 0;
  303. }
  304. if (! _pECB->ServerSupportFunction(
  305. _pECB->ConnID,
  306. HSE_REQ_VECTOR_SEND,
  307. &_RespVector,
  308. NULL,
  309. NULL) )
  310. {
  311. //
  312. // No use in trying to reset _fHeadersSent in case of failure
  313. //
  314. return HRESULT_FROM_WIN32( GetLastError() );
  315. }
  316. *pfAsyncPending = TRUE;
  317. return S_OK;
  318. }