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.

2690 lines
60 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. w3request.cxx
  5. Abstract:
  6. Friendly wrapper for UL_HTTP_REQUEST
  7. Author:
  8. Bilal Alam (balam) 13-Dec-1999
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. //
  16. // LocalHost address used to determining whether request is local/remote
  17. //
  18. #define LOCAL127 0x0100007F // 127.0.0.1
  19. #define DEFAULT_PORT 80
  20. #define DEFAULT_PORT_SECURE 443
  21. PHOSTENT W3_REQUEST::sm_pHostEnt;
  22. ALLOC_CACHE_HANDLER * W3_CLONE_REQUEST::sm_pachCloneRequests;
  23. DWORD
  24. W3_REQUEST::QueryLocalAddress(
  25. VOID
  26. ) const
  27. /*++
  28. Routine Description:
  29. Get the local IP address connected to (assumes IPV4)
  30. Arguments:
  31. None
  32. Return Value:
  33. Address
  34. --*/
  35. {
  36. HTTP_NETWORK_ADDRESS_IPV4 * pAddress;
  37. DBG_ASSERT( _pUlHttpRequest->Address.LocalAddressType == HTTP_NETWORK_ADDRESS_TYPE_IPV4 );
  38. pAddress = (HTTP_NETWORK_ADDRESS_IPV4 *)_pUlHttpRequest->Address.pLocalAddress;
  39. return pAddress->IpAddress;
  40. }
  41. VOID
  42. W3_REQUEST::RemoveDav(
  43. VOID
  44. )
  45. /*++
  46. Routine Description:
  47. Remove DAV'ness of request
  48. Arguments:
  49. None
  50. Return Value:
  51. None
  52. --*/
  53. {
  54. //
  55. // Remove translate header
  56. //
  57. DeleteHeader( "Translate" );
  58. DeleteHeader( "If" );
  59. DeleteHeader( "Lock-Token" );
  60. }
  61. BOOL
  62. W3_REQUEST::IsSuspectUrl(
  63. VOID
  64. )
  65. /*++
  66. Routine Description:
  67. Is the URL for this request look suspect?
  68. Suspect means there is a ./ pattern in it which could cause a metabase
  69. equivilency issue.
  70. Arguments:
  71. None
  72. Return Value:
  73. TRUE if the URL is suspect, else FALSE
  74. --*/
  75. {
  76. WCHAR * pszDotSlash;
  77. WCHAR * pszUrl;
  78. WCHAR chTemp;
  79. pszUrl = _pUlHttpRequest->CookedUrl.pAbsPath;
  80. //
  81. // URL UL gives us has backslashes flipped. But it is not 0 terminated
  82. //
  83. chTemp = pszUrl[ _pUlHttpRequest->CookedUrl.AbsPathLength / 2 ];
  84. pszUrl[ _pUlHttpRequest->CookedUrl.AbsPathLength / 2 ] = L'\0';
  85. pszDotSlash = wcsstr( pszUrl, L"./" );
  86. pszUrl[ _pUlHttpRequest->CookedUrl.AbsPathLength / 2 ] = chTemp;
  87. if ( pszDotSlash != NULL )
  88. {
  89. return TRUE;
  90. }
  91. //
  92. // If the URL ends with a ., it is also suspect
  93. //
  94. if ( pszUrl[ _pUlHttpRequest->CookedUrl.AbsPathLength / 2 - 1 ] == L'.' )
  95. {
  96. return TRUE;
  97. }
  98. return FALSE;
  99. }
  100. BOOL
  101. W3_REQUEST::QueryClientWantsDisconnect(
  102. VOID
  103. )
  104. /*++
  105. Routine Description:
  106. Returns whether the client wants to disconnect, based on its version and
  107. connection: headers
  108. Arguments:
  109. None
  110. Return Value:
  111. TRUE if client wants to disconnect
  112. --*/
  113. {
  114. HTTP_VERSION version;
  115. CHAR * pszConnection;
  116. version = QueryVersion();
  117. //
  118. // If 0.9, then disconnect
  119. //
  120. if ( HTTP_EQUAL_VERSION( version, 0, 9 ) )
  121. {
  122. return TRUE;
  123. }
  124. //
  125. // If 1.0 and Connection: keep-alive isn't present
  126. //
  127. if ( HTTP_EQUAL_VERSION( version, 1, 0 ) )
  128. {
  129. pszConnection = GetHeader( HttpHeaderConnection );
  130. if ( pszConnection == NULL ||
  131. _stricmp( pszConnection, "Keep-Alive" ) != 0 )
  132. {
  133. return TRUE;
  134. }
  135. }
  136. //
  137. // If 1.1 and Connection: Close is present
  138. //
  139. if ( HTTP_EQUAL_VERSION( version, 1, 1 ) )
  140. {
  141. pszConnection = GetHeader( HttpHeaderConnection );
  142. if ( pszConnection != NULL &&
  143. _stricmp( pszConnection, "Close" ) == 0 )
  144. {
  145. return TRUE;
  146. }
  147. }
  148. return FALSE;
  149. }
  150. HRESULT
  151. W3_REQUEST::SetHeadersByStream(
  152. CHAR * pszStream
  153. )
  154. /*++
  155. Routine Description:
  156. Set request headers based on given stream
  157. Arguments:
  158. pszHeaderStream - Stream to parse and set headers off
  159. Return Value:
  160. HRESULT
  161. --*/
  162. {
  163. CHAR * pszCursor;
  164. CHAR * pszEnd;
  165. CHAR * pszColon;
  166. HRESULT hr = NO_ERROR;
  167. STACK_STRA( strHeaderLine, 128 );
  168. STACK_STRA( strHeaderName, 32 );
  169. STACK_STRA( strHeaderValue, 64 );
  170. if ( pszStream == NULL )
  171. {
  172. DBG_ASSERT( FALSE );
  173. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  174. }
  175. //
  176. // \r\n delimited
  177. //
  178. pszCursor = pszStream;
  179. while ( pszCursor != NULL && *pszCursor != '\0' )
  180. {
  181. if ( *pszCursor == '\r' && *(pszCursor + 1) == '\n' )
  182. {
  183. break;
  184. }
  185. pszEnd = strstr( pszCursor, "\r\n" );
  186. if ( pszEnd == NULL )
  187. {
  188. break;
  189. }
  190. //
  191. // Split out a line
  192. //
  193. hr = strHeaderLine.Copy( pszCursor,
  194. DIFF(pszEnd - pszCursor) );
  195. if ( FAILED( hr ) )
  196. {
  197. goto Finished;
  198. }
  199. //
  200. // Advance the cursor the right after the \r\n
  201. //
  202. pszCursor = pszEnd + 2;
  203. //
  204. // Split the line above into header:value
  205. //
  206. pszColon = strchr( strHeaderLine.QueryStr(), ':' );
  207. if ( pszColon == NULL )
  208. {
  209. //
  210. // Expecting name:value. Just skip for now
  211. //
  212. continue;
  213. }
  214. hr = strHeaderName.Copy( strHeaderLine.QueryStr(),
  215. DIFF(pszColon - strHeaderLine.QueryStr()) );
  216. if ( FAILED( hr ) )
  217. {
  218. goto Finished;
  219. }
  220. //
  221. // Skip the first space after the : if there is one
  222. //
  223. if ( pszColon[ 1 ] == ' ' )
  224. {
  225. pszColon++;
  226. }
  227. hr = strHeaderValue.Copy( pszColon + 1 );
  228. if ( FAILED( hr ) )
  229. {
  230. goto Finished;
  231. }
  232. //
  233. // Add the header to the response
  234. //
  235. hr = SetHeader( strHeaderName,
  236. strHeaderValue,
  237. FALSE );
  238. if ( FAILED( hr ) )
  239. {
  240. goto Finished;
  241. }
  242. }
  243. Finished:
  244. return hr;
  245. }
  246. DWORD
  247. W3_REQUEST::QueryRemoteAddress(
  248. VOID
  249. ) const
  250. /*++
  251. Routine Description:
  252. Get the remote IP address connecting to us (assumes IPV4)
  253. Arguments:
  254. None
  255. Return Value:
  256. Address
  257. --*/
  258. {
  259. HTTP_NETWORK_ADDRESS_IPV4 * pAddress;
  260. DBG_ASSERT( _pUlHttpRequest->Address.RemoteAddressType == HTTP_NETWORK_ADDRESS_TYPE_IPV4 );
  261. pAddress = (HTTP_NETWORK_ADDRESS_IPV4*) _pUlHttpRequest->Address.pRemoteAddress;
  262. return pAddress->IpAddress;
  263. }
  264. USHORT
  265. W3_REQUEST::QueryLocalPort(
  266. VOID
  267. ) const
  268. {
  269. HTTP_NETWORK_ADDRESS_IPV4 * pAddress;
  270. DBG_ASSERT( _pUlHttpRequest->Address.LocalAddressType == HTTP_NETWORK_ADDRESS_TYPE_IPV4 );
  271. pAddress = (HTTP_NETWORK_ADDRESS_IPV4*) _pUlHttpRequest->Address.pLocalAddress;
  272. return pAddress->Port;
  273. }
  274. USHORT
  275. W3_REQUEST::QueryRemotePort(
  276. VOID
  277. ) const
  278. {
  279. HTTP_NETWORK_ADDRESS_IPV4 * pAddress;
  280. DBG_ASSERT( _pUlHttpRequest->Address.RemoteAddressType == HTTP_NETWORK_ADDRESS_TYPE_IPV4 );
  281. pAddress = (HTTP_NETWORK_ADDRESS_IPV4*) _pUlHttpRequest->Address.pRemoteAddress;
  282. return pAddress->Port;
  283. }
  284. BOOL
  285. W3_REQUEST::IsProxyRequest(
  286. VOID
  287. )
  288. /*++
  289. Description:
  290. Check if request was issued by a proxy, as determined by following rules :
  291. - "Via:" header is present (HTTP/1.1)
  292. - "Forwarded:" header is present (some HTTP/1.0 implementations)
  293. - "User-Agent:" contains "via ..." (CERN proxy)
  294. Arguments:
  295. None
  296. Returns:
  297. TRUE if client request was issued by proxy
  298. --*/
  299. {
  300. CHAR * pUserAgent;
  301. UINT cUserAgent;
  302. CHAR * pEnd;
  303. if ( GetHeader( HttpHeaderVia ) || GetHeader( "Forward" ) )
  304. {
  305. return TRUE;
  306. }
  307. if ( pUserAgent = GetHeader( HttpHeaderUserAgent ) )
  308. {
  309. cUserAgent = strlen( pUserAgent );
  310. pEnd = pUserAgent + cUserAgent - 3;
  311. //
  312. // scan for "[Vv]ia[ :]" in User-Agent: header
  313. //
  314. while ( pUserAgent < pEnd )
  315. {
  316. if ( *pUserAgent == 'V' || *pUserAgent == 'v' )
  317. {
  318. if ( pUserAgent[1] == 'i' &&
  319. pUserAgent[2] == 'a' &&
  320. (pUserAgent[3] == ' ' || pUserAgent[3] == ':') )
  321. {
  322. return TRUE;
  323. }
  324. }
  325. ++pUserAgent;
  326. }
  327. }
  328. return FALSE;
  329. }
  330. BOOL
  331. W3_REQUEST::IsChunkedRequest(
  332. VOID
  333. )
  334. /*++
  335. Description:
  336. Check if request is chunk transfer encoded.
  337. Arguments:
  338. None
  339. Returns:
  340. TRUE if client request has a "transfer-encoding: chunked"
  341. header.
  342. --*/
  343. {
  344. CHAR * pTransferEncoding;
  345. UINT cTransferEncoding;
  346. BOOL fRet = FALSE;
  347. if ( pTransferEncoding = GetHeader( HttpHeaderTransferEncoding ) )
  348. {
  349. fRet = ( _stricmp( pTransferEncoding, "chunked" ) == 0 );
  350. }
  351. return fRet;
  352. }
  353. HRESULT
  354. W3_REQUEST::GetAuthType(
  355. STRA * pstrAuthType
  356. )
  357. /*++
  358. Routine Description:
  359. Determine the auth type for this request. Auth type is the string
  360. after the authorization header (and before the space if there).
  361. Eg. Authorization: Basic FOOBAR ==> AuthType is Basic
  362. Authorization: NTLM ==> AuthType is NTLM
  363. And of course if client cert mapping happened, type is "SSL/PCT"
  364. Arguments:
  365. pstrAuthType - Filled with auth type
  366. Return Value:
  367. HRESULT
  368. --*/
  369. {
  370. CHAR * pszAuthType;
  371. CHAR * pszSpace;
  372. HRESULT hr;
  373. if ( pstrAuthType == NULL )
  374. {
  375. DBG_ASSERT( FALSE );
  376. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  377. }
  378. //
  379. // First check for client cert mapping
  380. //
  381. if ( QueryClientCertInfo() != NULL &&
  382. QueryClientCertInfo()->Token != NULL )
  383. {
  384. return pstrAuthType->Copy( "SSL/PCT" );
  385. }
  386. //
  387. // Now check for the Authorization: header
  388. //
  389. pszAuthType = GetHeader( HttpHeaderAuthorization );
  390. if ( pszAuthType == NULL )
  391. {
  392. pstrAuthType->Reset();
  393. hr = NO_ERROR;
  394. }
  395. else
  396. {
  397. pszSpace = strchr( pszAuthType, ' ' );
  398. if ( pszSpace == NULL )
  399. {
  400. hr = pstrAuthType->Copy( pszAuthType );
  401. }
  402. else
  403. {
  404. hr = pstrAuthType->Copy( pszAuthType,
  405. DIFF( pszSpace - pszAuthType ) );
  406. }
  407. }
  408. return hr;
  409. }
  410. BOOL
  411. W3_REQUEST::IsLocalRequest(
  412. VOID
  413. ) const
  414. /*++
  415. Routine Description:
  416. Determines whether current request is a local request. This is used
  417. since certain vroot permissions can be specified for remote/local
  418. Arguments:
  419. None
  420. Return Value:
  421. TRUE if this is a local request
  422. --*/
  423. {
  424. DWORD localAddress = QueryLocalAddress();
  425. DWORD remoteAddress = QueryRemoteAddress();
  426. CHAR** list;
  427. PIN_ADDR p;
  428. //
  429. // Are the remote/local addresses the same?
  430. //
  431. if ( localAddress == remoteAddress )
  432. {
  433. return TRUE;
  434. }
  435. //
  436. // Are either equal to 127.0.0.1
  437. //
  438. if ( localAddress == LOCAL127 ||
  439. remoteAddress == LOCAL127 )
  440. {
  441. return TRUE;
  442. }
  443. //
  444. // Is the remote address equal to one of the host addresses
  445. //
  446. list = sm_pHostEnt->h_addr_list;
  447. while ( (p = (PIN_ADDR)*list++) != NULL )
  448. {
  449. if ( p->s_addr == remoteAddress )
  450. {
  451. return TRUE;
  452. }
  453. }
  454. return FALSE;
  455. }
  456. HRESULT
  457. W3_REQUEST::BuildFullUrl(
  458. STRU& strPath,
  459. STRU * pstrRedirect,
  460. BOOL fIncludeParameters
  461. )
  462. /*++
  463. Routine Description:
  464. Create a new URL while maintaining host/port/protocol/query-string of
  465. original request
  466. Arguments:
  467. strPath - New path portion of URL
  468. pstrRedirect - String filled with new full URL
  469. fIncludeParameters - TRUE if original query string should be copied too
  470. Return Value:
  471. HRESULT
  472. --*/
  473. {
  474. HRESULT hr = NO_ERROR;
  475. if ( pstrRedirect == NULL )
  476. {
  477. DBG_ASSERT( FALSE );
  478. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  479. }
  480. hr = pstrRedirect->Copy( IsSecureRequest() ? L"https://" : L"http://" );
  481. if ( FAILED( hr ) )
  482. {
  483. return hr;
  484. }
  485. LPWSTR pszColon = wcschr( _pUlHttpRequest->CookedUrl.pHost, ':' );
  486. if ((pszColon != NULL) &&
  487. ((IsSecureRequest() && _wtoi(pszColon + 1) == DEFAULT_PORT_SECURE) ||
  488. (!IsSecureRequest() && _wtoi(pszColon + 1) == DEFAULT_PORT)))
  489. {
  490. hr = pstrRedirect->Append( _pUlHttpRequest->CookedUrl.pHost,
  491. DIFF(pszColon - _pUlHttpRequest->CookedUrl.pHost) );
  492. }
  493. else
  494. {
  495. hr = pstrRedirect->Append( _pUlHttpRequest->CookedUrl.pHost,
  496. _pUlHttpRequest->CookedUrl.HostLength / sizeof( WCHAR ) );
  497. }
  498. if ( FAILED( hr ) )
  499. {
  500. return hr;
  501. }
  502. hr = pstrRedirect->Append( strPath );
  503. if ( FAILED( hr ) )
  504. {
  505. return hr;
  506. }
  507. if ( fIncludeParameters &&
  508. _pUlHttpRequest->CookedUrl.pQueryString != NULL )
  509. {
  510. //
  511. // UL_HTTP_REQUEST::QueryString already contains the '?'
  512. //
  513. hr = pstrRedirect->Append(
  514. _pUlHttpRequest->CookedUrl.pQueryString,
  515. _pUlHttpRequest->CookedUrl.QueryStringLength / sizeof(WCHAR));
  516. if ( FAILED( hr ) )
  517. {
  518. return hr;
  519. }
  520. }
  521. return S_OK;
  522. }
  523. HRESULT
  524. W3_REQUEST::BuildFullUrl(
  525. STRA& strPath,
  526. STRA * pstrRedirect,
  527. BOOL fIncludeParameters
  528. )
  529. /*++
  530. Routine Description:
  531. Create a new URL while maintaining host/port/protocol/query-string of
  532. original request
  533. Arguments:
  534. strPath - New path portion of URL
  535. pstrRedirect - String filled with new full URL
  536. fIncludeParameters - TRUE if original query string should be copied too
  537. Return Value:
  538. HRESULT
  539. --*/
  540. {
  541. HRESULT hr = NO_ERROR;
  542. if ( pstrRedirect == NULL )
  543. {
  544. DBG_ASSERT( FALSE );
  545. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  546. }
  547. hr = pstrRedirect->Copy( IsSecureRequest() ? "https://" : "http://" );
  548. if ( FAILED( hr ) )
  549. {
  550. return hr;
  551. }
  552. LPWSTR pszColon = wcschr( _pUlHttpRequest->CookedUrl.pHost, ':' );
  553. if ((pszColon != NULL) &&
  554. ((IsSecureRequest() && _wtoi(pszColon + 1) == DEFAULT_PORT_SECURE) ||
  555. (!IsSecureRequest() && _wtoi(pszColon + 1) == DEFAULT_PORT)))
  556. {
  557. hr = pstrRedirect->AppendW( _pUlHttpRequest->CookedUrl.pHost,
  558. DIFF(pszColon - _pUlHttpRequest->CookedUrl.pHost) );
  559. }
  560. else
  561. {
  562. hr = pstrRedirect->AppendW( _pUlHttpRequest->CookedUrl.pHost,
  563. _pUlHttpRequest->CookedUrl.HostLength / sizeof( WCHAR ) );
  564. }
  565. if ( FAILED( hr ) )
  566. {
  567. return hr;
  568. }
  569. hr = pstrRedirect->Append( strPath );
  570. if ( FAILED( hr ) )
  571. {
  572. return hr;
  573. }
  574. if ( fIncludeParameters &&
  575. _pUlHttpRequest->CookedUrl.pQueryString != NULL )
  576. {
  577. //
  578. // UL_HTTP_REQUEST::QueryString already contains the '?'
  579. //
  580. hr = pstrRedirect->AppendW(
  581. _pUlHttpRequest->CookedUrl.pQueryString,
  582. _pUlHttpRequest->CookedUrl.QueryStringLength / sizeof(WCHAR));
  583. if ( FAILED( hr ) )
  584. {
  585. return hr;
  586. }
  587. }
  588. return S_OK;
  589. }
  590. CHAR *
  591. W3_REQUEST::GetHeader(
  592. CHAR * pszHeaderName
  593. )
  594. /*++
  595. Routine Description:
  596. Get a request header and copy it into supplied buffer
  597. Arguments:
  598. pszHeaderName - Name of header to get
  599. Return Value:
  600. WCHAR pointer pointed to the header, NULL if no such header
  601. --*/
  602. {
  603. ULONG ulHeaderIndex = UNKNOWN_INDEX;
  604. HTTP_REQUEST_HEADERS * pHeaders = &(_pUlHttpRequest->Headers);
  605. HRESULT hr = HRESULT_FROM_WIN32( ERROR_INVALID_INDEX );
  606. DBG_ASSERT( pszHeaderName != NULL );
  607. //
  608. // First check whether this header is a known header
  609. //
  610. ulHeaderIndex = REQUEST_HEADER_HASH::GetIndex( pszHeaderName );
  611. if ( ulHeaderIndex == UNKNOWN_INDEX )
  612. {
  613. //
  614. // Need to iterate thru unknown headers
  615. //
  616. for ( DWORD i = 0;
  617. i < pHeaders->UnknownHeaderCount;
  618. i++ )
  619. {
  620. if ( _stricmp( pszHeaderName,
  621. pHeaders->pUnknownHeaders[ i ].pName ) == 0 )
  622. {
  623. return pHeaders->pUnknownHeaders[ i ].pRawValue;
  624. }
  625. }
  626. return NULL;
  627. }
  628. else
  629. {
  630. //
  631. // Known header
  632. //
  633. DBG_ASSERT( ulHeaderIndex < HttpHeaderRequestMaximum );
  634. return pHeaders->pKnownHeaders[ ulHeaderIndex ].pRawValue;
  635. }
  636. }
  637. HRESULT
  638. W3_REQUEST::GetHeader(
  639. CHAR * pszHeaderName,
  640. DWORD cchHeaderName,
  641. STRA * pstrHeaderValue,
  642. BOOL fIsUnknownHeader
  643. )
  644. /*++
  645. Routine Description:
  646. Get a request header and copy it into supplied buffer
  647. Arguments:
  648. pszHeaderName - Header name
  649. cchHeaderName - Length of header name
  650. pstrHeaderValue - Filled with header value
  651. fIsUnknownHeader - (optional) set to TRUE if header is unknown
  652. and we can avoid doing header hash lookup
  653. Return Value:
  654. HRESULT
  655. --*/
  656. {
  657. ULONG ulHeaderIndex = UNKNOWN_INDEX;
  658. HTTP_REQUEST_HEADERS * pHeaders = &(_pUlHttpRequest->Headers);
  659. HRESULT hr = HRESULT_FROM_WIN32( ERROR_INVALID_INDEX );
  660. if ( pszHeaderName == NULL )
  661. {
  662. DBG_ASSERT( FALSE );
  663. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  664. }
  665. //
  666. // First check whether this header is a known header
  667. //
  668. if ( !fIsUnknownHeader )
  669. {
  670. ulHeaderIndex = REQUEST_HEADER_HASH::GetIndex( pszHeaderName );
  671. }
  672. if ( ulHeaderIndex == UNKNOWN_INDEX )
  673. {
  674. //
  675. // Need to iterate thru unknown headers
  676. //
  677. for ( DWORD i = 0;
  678. i < pHeaders->UnknownHeaderCount;
  679. i++ )
  680. {
  681. if ( cchHeaderName == pHeaders->pUnknownHeaders[ i ].NameLength &&
  682. _stricmp( pszHeaderName,
  683. pHeaders->pUnknownHeaders[ i ].pName ) == 0 )
  684. {
  685. hr = pstrHeaderValue->Copy(
  686. pHeaders->pUnknownHeaders[ i ].pRawValue,
  687. pHeaders->pUnknownHeaders[ i ].RawValueLength );
  688. break;
  689. }
  690. }
  691. }
  692. else
  693. {
  694. //
  695. // Known header
  696. //
  697. DBG_ASSERT( ulHeaderIndex < HttpHeaderRequestMaximum );
  698. if ( pHeaders->pKnownHeaders[ ulHeaderIndex ].pRawValue != NULL )
  699. {
  700. hr = pstrHeaderValue->Copy(
  701. pHeaders->pKnownHeaders[ ulHeaderIndex ].pRawValue,
  702. pHeaders->pKnownHeaders[ ulHeaderIndex ].RawValueLength);
  703. }
  704. else
  705. {
  706. hr = HRESULT_FROM_WIN32( ERROR_INVALID_INDEX );
  707. }
  708. }
  709. return hr;
  710. }
  711. HRESULT
  712. W3_REQUEST::DeleteHeader(
  713. CHAR * pszHeaderName
  714. )
  715. /*++
  716. Routine Description:
  717. Delete a request header
  718. Arguments:
  719. pszHeaderName - Header to delete
  720. Return Value:
  721. HRESULT
  722. --*/
  723. {
  724. ULONG ulHeaderIndex;
  725. HRESULT hr;
  726. HTTP_UNKNOWN_HEADER * pUnknownHeader;
  727. //
  728. // Is this a known header? If so, we can just set by reference now
  729. // since we have copied the header value
  730. //
  731. ulHeaderIndex = REQUEST_HEADER_HASH::GetIndex( pszHeaderName );
  732. if ( ulHeaderIndex != UNKNOWN_INDEX &&
  733. ulHeaderIndex < HttpHeaderResponseMaximum )
  734. {
  735. _pUlHttpRequest->Headers.pKnownHeaders[ ulHeaderIndex ].pRawValue = NULL;
  736. _pUlHttpRequest->Headers.pKnownHeaders[ ulHeaderIndex ].RawValueLength = 0;
  737. }
  738. else
  739. {
  740. //
  741. // Unknown header. First check if it exists
  742. //
  743. for ( DWORD i = 0;
  744. i < _pUlHttpRequest->Headers.UnknownHeaderCount;
  745. i++ )
  746. {
  747. pUnknownHeader = &(_pUlHttpRequest->Headers.pUnknownHeaders[ i ]);
  748. DBG_ASSERT( pUnknownHeader != NULL );
  749. if ( _stricmp( pUnknownHeader->pName, pszHeaderName ) == 0 )
  750. {
  751. break;
  752. }
  753. }
  754. if ( i < _pUlHttpRequest->Headers.UnknownHeaderCount )
  755. {
  756. //
  757. // Now shrink the array to remove the header
  758. //
  759. memmove( _pUlHttpRequest->Headers.pUnknownHeaders + i,
  760. _pUlHttpRequest->Headers.pUnknownHeaders + i + 1,
  761. ( _pUlHttpRequest->Headers.UnknownHeaderCount - i - 1 ) *
  762. sizeof( HTTP_UNKNOWN_HEADER ) );
  763. _pUlHttpRequest->Headers.UnknownHeaderCount--;
  764. }
  765. }
  766. return NO_ERROR;
  767. }
  768. HRESULT
  769. W3_REQUEST::SetHeader(
  770. STRA & strHeaderName,
  771. STRA & strHeaderValue,
  772. BOOL fAppend
  773. )
  774. /*++
  775. Routine Description:
  776. Set a request header
  777. Arguments:
  778. strHeaderName - Name of header to set
  779. strHeaderValue - New header value to set
  780. fAppend - If TRUE, the existing header value is appended to, else it is
  781. replaced
  782. Return Value:
  783. HRESULT
  784. --*/
  785. {
  786. CHAR * pszNewName = NULL;
  787. CHAR * pszNewValue = NULL;
  788. STACK_STRA( strOldHeaderValue, 256 );
  789. STRA * pstrNewHeaderValue = NULL;
  790. HRESULT hr;
  791. ULONG index;
  792. //
  793. // If we're appending, then get the old header value (if any) and
  794. // append the new value (with a comma delimiter)
  795. //
  796. if ( fAppend )
  797. {
  798. hr = GetHeader( strHeaderName, &strOldHeaderValue );
  799. if ( FAILED( hr ) )
  800. {
  801. pstrNewHeaderValue = &strHeaderValue;
  802. hr = NO_ERROR;
  803. }
  804. else
  805. {
  806. hr = strOldHeaderValue.Append( ",", 1 );
  807. if ( FAILED( hr ) )
  808. {
  809. return hr;
  810. }
  811. hr = strOldHeaderValue.Append( strHeaderValue );
  812. if ( FAILED( hr ) )
  813. {
  814. return hr;
  815. }
  816. pstrNewHeaderValue = &strOldHeaderValue;
  817. }
  818. }
  819. else
  820. {
  821. pstrNewHeaderValue = &strHeaderValue;
  822. }
  823. DBG_ASSERT( pstrNewHeaderValue != NULL );
  824. //
  825. // pstrNewHeaderValue will point to either "old,new" or "new"
  826. //
  827. hr = _HeaderBuffer.AllocateSpace( pstrNewHeaderValue->QueryStr(),
  828. pstrNewHeaderValue->QueryCCH(),
  829. &pszNewValue );
  830. if ( FAILED( hr ) )
  831. {
  832. return hr;
  833. }
  834. //
  835. // Is this a known header?
  836. //
  837. index = REQUEST_HEADER_HASH::GetIndex( strHeaderName.QueryStr() );
  838. if ( index == UNKNOWN_INDEX )
  839. {
  840. hr = _HeaderBuffer.AllocateSpace( strHeaderName.QueryStr(),
  841. strHeaderName.QueryCCH(),
  842. &pszNewName );
  843. if ( FAILED( hr ) )
  844. {
  845. return hr;
  846. }
  847. //
  848. // Find the header in the unknown list
  849. //
  850. for ( DWORD i = 0;
  851. i < _pUlHttpRequest->Headers.UnknownHeaderCount;
  852. i++ )
  853. {
  854. if ( _strnicmp( strHeaderName.QueryStr(),
  855. _pUlHttpRequest->Headers.pUnknownHeaders[ i ].pName,
  856. strHeaderName.QueryCCH() ) == 0 )
  857. {
  858. break;
  859. }
  860. }
  861. //
  862. // If we found the unknown header, then this is much simpler
  863. //
  864. if ( i < _pUlHttpRequest->Headers.UnknownHeaderCount )
  865. {
  866. _pUlHttpRequest->Headers.pUnknownHeaders[i].pRawValue =
  867. pszNewValue;
  868. _pUlHttpRequest->Headers.pUnknownHeaders[i].RawValueLength =
  869. (USHORT) pstrNewHeaderValue->QueryCB();
  870. }
  871. else
  872. {
  873. HTTP_UNKNOWN_HEADER *pUnknownHeaders;
  874. DWORD cCount;
  875. //
  876. // Fun. Need to add a new unknown header
  877. //
  878. cCount = _pUlHttpRequest->Headers.UnknownHeaderCount;
  879. //
  880. // BUGBUG: are we leaking this memory?
  881. //
  882. pUnknownHeaders = (HTTP_UNKNOWN_HEADER *) LocalAlloc(
  883. LPTR,
  884. sizeof( HTTP_UNKNOWN_HEADER ) *
  885. ( cCount+1 ) );
  886. if ( pUnknownHeaders == NULL )
  887. {
  888. return HRESULT_FROM_WIN32( GetLastError() );
  889. }
  890. memcpy( pUnknownHeaders,
  891. _pUlHttpRequest->Headers.pUnknownHeaders,
  892. sizeof( HTTP_UNKNOWN_HEADER ) * (cCount) );
  893. pUnknownHeaders[ cCount ].pName = pszNewName;
  894. pUnknownHeaders[ cCount ].NameLength = (USHORT)strHeaderName.QueryCB();
  895. pUnknownHeaders[ cCount ].pRawValue = pszNewValue;
  896. pUnknownHeaders[ cCount ].RawValueLength = (USHORT) pstrNewHeaderValue->QueryCB();
  897. //
  898. // Patch in the new array
  899. //
  900. if ( _pExtraUnknown != NULL )
  901. {
  902. LocalFree( _pExtraUnknown );
  903. }
  904. _pExtraUnknown = pUnknownHeaders;
  905. _pUlHttpRequest->Headers.pUnknownHeaders = pUnknownHeaders;
  906. _pUlHttpRequest->Headers.UnknownHeaderCount++;
  907. }
  908. }
  909. else
  910. {
  911. //
  912. // The easy case. Known header
  913. //
  914. _pUlHttpRequest->Headers.pKnownHeaders[ index ].pRawValue = pszNewValue;
  915. _pUlHttpRequest->Headers.pKnownHeaders[ index ].RawValueLength = (USHORT) pstrNewHeaderValue->QueryCB();
  916. }
  917. return S_OK;
  918. }
  919. HRESULT
  920. W3_REQUEST::GetVersionString(
  921. STRA * pstrVersion
  922. )
  923. /*++
  924. Routine Description:
  925. Get version string of request (like "HTTP/1.1")
  926. Arguments:
  927. pstrVersion - Filled in with version
  928. Return Value:
  929. HRESULT
  930. --*/
  931. {
  932. HRESULT hr;
  933. CHAR pszMajorVersion[6];
  934. CHAR pszMinorVersion[6];
  935. _itoa(_pUlHttpRequest->Version.MajorVersion, pszMajorVersion, 10);
  936. _itoa(_pUlHttpRequest->Version.MinorVersion, pszMinorVersion, 10);
  937. if (FAILED(hr = pstrVersion->Copy("HTTP/", 5)) ||
  938. FAILED(hr = pstrVersion->Append(pszMajorVersion)) ||
  939. FAILED(hr = pstrVersion->Append(".", 1)) ||
  940. FAILED(hr = pstrVersion->Append(pszMinorVersion)))
  941. {
  942. return hr;
  943. }
  944. return S_OK;
  945. }
  946. HRESULT
  947. W3_REQUEST::GetVerbString(
  948. STRA * pstrVerb
  949. )
  950. /*++
  951. Routine Description:
  952. Get the HTTP verb from the request
  953. Arguments:
  954. pstrVerb - Filled in with verb
  955. Return Value:
  956. HRESULT
  957. --*/
  958. {
  959. USHORT cchVerb;
  960. CHAR *pszVerb = METHOD_HASH::GetString(_pUlHttpRequest->Verb, &cchVerb);
  961. if (pszVerb != NULL)
  962. {
  963. return pstrVerb->Copy(pszVerb, cchVerb);
  964. }
  965. else
  966. {
  967. return pstrVerb->Copy(_pUlHttpRequest->pUnknownVerb,
  968. _pUlHttpRequest->UnknownVerbLength);
  969. }
  970. }
  971. VOID
  972. W3_REQUEST::QueryVerb(
  973. CHAR **ppszVerb,
  974. USHORT *pcchVerb)
  975. /*++
  976. Get the HTTP verb from the request
  977. --*/
  978. {
  979. *ppszVerb = METHOD_HASH::GetString(_pUlHttpRequest->Verb, pcchVerb);
  980. if (*ppszVerb == NULL)
  981. {
  982. *ppszVerb = _pUlHttpRequest->pUnknownVerb;
  983. *pcchVerb = _pUlHttpRequest->UnknownVerbLength;
  984. }
  985. }
  986. HRESULT
  987. W3_REQUEST::SetVerb(
  988. STRA & strVerb
  989. )
  990. /*++
  991. Routine Description:
  992. Change the request verb (done in PREPROC_HEADER ISAPI filters)
  993. Arguments:
  994. strVerb - New verb
  995. Return Value:
  996. HRESULT
  997. --*/
  998. {
  999. HRESULT hr;
  1000. CHAR *pszNewVerb;
  1001. HTTP_VERB Verb = (HTTP_VERB)METHOD_HASH::GetIndex(strVerb.QueryStr());
  1002. _pUlHttpRequest->Verb = Verb;
  1003. if ( Verb == HttpVerbUnknown )
  1004. {
  1005. //
  1006. // Handle unknown verbs
  1007. //
  1008. hr = _HeaderBuffer.AllocateSpace( strVerb.QueryStr(),
  1009. strVerb.QueryCCH(),
  1010. &pszNewVerb );
  1011. if ( FAILED( hr ) )
  1012. {
  1013. return hr;
  1014. }
  1015. _pUlHttpRequest->pUnknownVerb = pszNewVerb;
  1016. _pUlHttpRequest->UnknownVerbLength = (USHORT) strVerb.QueryCCH();
  1017. }
  1018. else
  1019. {
  1020. _pUlHttpRequest->pUnknownVerb = NULL;
  1021. _pUlHttpRequest->UnknownVerbLength = 0;
  1022. }
  1023. return S_OK;
  1024. }
  1025. HRESULT
  1026. W3_REQUEST::SetVersion(
  1027. STRA& strVersion
  1028. )
  1029. /*++
  1030. Routine Description:
  1031. strVersion - Set the request version (done by PREPROC_HEADER filters)
  1032. Arguments:
  1033. strVersion - Version string
  1034. Return Value:
  1035. HRESULT
  1036. --*/
  1037. {
  1038. HRESULT hr = S_OK;
  1039. //
  1040. // BUGBUG: Probably not the fastest way to do this
  1041. //
  1042. if ( strcmp( strVersion.QueryStr(), "HTTP/1.1" ) == 0 )
  1043. {
  1044. _pUlHttpRequest->Version.MajorVersion = 1;
  1045. _pUlHttpRequest->Version.MinorVersion = 1;
  1046. }
  1047. else if ( strcmp( strVersion.QueryStr(), "HTTP/1.0" ) == 0 )
  1048. {
  1049. _pUlHttpRequest->Version.MajorVersion = 1;
  1050. _pUlHttpRequest->Version.MinorVersion = 0;
  1051. }
  1052. else if ( strcmp( strVersion.QueryStr(), "HTTP/0.9" ) == 0 )
  1053. {
  1054. _pUlHttpRequest->Version.MajorVersion = 0;
  1055. _pUlHttpRequest->Version.MinorVersion = 9;
  1056. }
  1057. else
  1058. {
  1059. hr = HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  1060. }
  1061. return hr;
  1062. }
  1063. HRESULT
  1064. W3_REQUEST::SetNewPreloadedEntityBody(
  1065. VOID * pvBuffer,
  1066. DWORD cbBuffer
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. Change the preloaded entity body for this request
  1071. Arguments:
  1072. pvBuffer - the buffer
  1073. cbBuffer - the size of the buffer
  1074. Return Value:
  1075. HRESULT
  1076. --*/
  1077. {
  1078. _InsertedEntityBodyChunk.DataChunkType = HttpDataChunkFromMemory;
  1079. _InsertedEntityBodyChunk.FromMemory.pBuffer = pvBuffer;
  1080. _InsertedEntityBodyChunk.FromMemory.BufferLength = cbBuffer;
  1081. _pUlHttpRequest->EntityChunkCount = 1;
  1082. _pUlHttpRequest->pEntityChunks = &_InsertedEntityBodyChunk;
  1083. return NO_ERROR;
  1084. }
  1085. HRESULT
  1086. W3_REQUEST::AppendEntityBody(
  1087. VOID * pvBuffer,
  1088. DWORD cbBuffer
  1089. )
  1090. /*
  1091. Description
  1092. Add the given entity to (any) entity already present
  1093. Arguments
  1094. pvBuffer - the buffer
  1095. cbBuffer - the size of the buffer
  1096. Return Value
  1097. HRESULT
  1098. */
  1099. {
  1100. DWORD cbAlreadyPresent = QueryAvailableBytes();
  1101. if ( cbAlreadyPresent == 0 )
  1102. {
  1103. return SetNewPreloadedEntityBody(pvBuffer, cbBuffer);
  1104. }
  1105. else
  1106. {
  1107. PVOID pbAlreadyPresent = QueryEntityBody();
  1108. if (!_buffEntityBodyPreload.Resize(cbBuffer + cbAlreadyPresent))
  1109. {
  1110. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1111. }
  1112. memcpy(_buffEntityBodyPreload.QueryPtr(),
  1113. pbAlreadyPresent,
  1114. cbAlreadyPresent);
  1115. memcpy((PBYTE)_buffEntityBodyPreload.QueryPtr() + cbAlreadyPresent,
  1116. pvBuffer,
  1117. cbBuffer);
  1118. }
  1119. return S_OK;
  1120. }
  1121. HRESULT
  1122. W3_REQUEST::SetUrl(
  1123. STRU & strNewUrl,
  1124. BOOL fResetQueryString // = TRUE
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Change the URL of the request
  1129. Arguments:
  1130. strNewUrl - New URL
  1131. fResetQueryString - TRUE if we should expect query string in strNewUrl
  1132. Return Value:
  1133. HRESULT
  1134. --*/
  1135. {
  1136. STACK_STRA ( straUrl, MAX_PATH );
  1137. HRESULT hr = S_OK;
  1138. DWORD lenToConvert = 0;
  1139. WCHAR * pFirstQuery = wcschr(strNewUrl.QueryStr(), L'?');
  1140. if (NULL == pFirstQuery)
  1141. {
  1142. lenToConvert = strNewUrl.QueryCCH();
  1143. }
  1144. else
  1145. {
  1146. lenToConvert = DIFF(pFirstQuery - strNewUrl.QueryStr());
  1147. }
  1148. if (FAILED(hr = straUrl.CopyWToUTF8(strNewUrl.QueryStr(), lenToConvert)))
  1149. {
  1150. return hr;
  1151. }
  1152. straUrl.AppendW(strNewUrl.QueryStr() + lenToConvert);
  1153. //
  1154. // SetUrlA does the canonicalization, unescaping
  1155. //
  1156. return SetUrlA( straUrl, fResetQueryString );
  1157. }
  1158. HRESULT
  1159. W3_REQUEST::SetUrlA(
  1160. STRA & strNewUrl,
  1161. BOOL fResetQueryString // = TRUE
  1162. )
  1163. /*++
  1164. Routine Description:
  1165. Change the URL of the request. Takes in an ANSI URL
  1166. Arguments:
  1167. strNewUrl - RAW version of URL which is also stored away
  1168. fResetQueryString - Should we expect query string in strNewUrl
  1169. Return Value:
  1170. HRESULT
  1171. --*/
  1172. {
  1173. DWORD cchNewUrl;
  1174. HRESULT hr = NO_ERROR;
  1175. ULONG cbBytesCopied;
  1176. LPWSTR pszQueryString;
  1177. CHAR * pszNewRawUrl;
  1178. LPWSTR pszNewFullUrl;
  1179. LPWSTR pszNewAbsPath;
  1180. STACK_STRU ( strFullUrl, MAX_PATH);
  1181. STACK_STRU ( strAbsPath, MAX_PATH);
  1182. //
  1183. // Need to process the URL ourselves. This means:
  1184. // -Unescaping, canonicalizing, and query-string-ilizing
  1185. //
  1186. //
  1187. // BUGBUG. Probably need to handle HTTP:// and HTTPS:// preceded URLs
  1188. // so that MS proxy can still work
  1189. //
  1190. hr = _HeaderBuffer.AllocateSpace( strNewUrl.QueryStr(),
  1191. strNewUrl.QueryCCH(),
  1192. &pszNewRawUrl );
  1193. if ( FAILED( hr ) )
  1194. {
  1195. goto Finished;
  1196. }
  1197. //
  1198. // Need to patch the UL_HTTP_REQUEST raw URL
  1199. //
  1200. _pUlHttpRequest->pRawUrl = pszNewRawUrl;
  1201. _pUlHttpRequest->RawUrlLength = (USHORT) strNewUrl.QueryCCH();
  1202. hr = _HeaderBuffer.AllocateSpace( (strNewUrl.QueryCCH() + 1)*sizeof(WCHAR),
  1203. &pszNewAbsPath );
  1204. if ( FAILED( hr ) )
  1205. {
  1206. goto Finished;
  1207. }
  1208. //
  1209. // Call into a UL ripped helper to do the parsing
  1210. //
  1211. hr = UlCleanAndCopyUrl( (PUCHAR)pszNewRawUrl,
  1212. strNewUrl.QueryCCH(),
  1213. &cbBytesCopied,
  1214. pszNewAbsPath,
  1215. &pszQueryString );
  1216. if ( FAILED( hr ) )
  1217. {
  1218. goto Finished;
  1219. }
  1220. //
  1221. // Need to patch the UL_HTTP_REQUEST AbsPath and QueryString
  1222. //
  1223. _pUlHttpRequest->CookedUrl.pAbsPath = pszNewAbsPath;
  1224. if ( pszQueryString != NULL )
  1225. {
  1226. _pUlHttpRequest->CookedUrl.pQueryString = pszQueryString;
  1227. _pUlHttpRequest->CookedUrl.AbsPathLength = DIFF(pszQueryString - pszNewAbsPath) * sizeof(WCHAR);
  1228. _pUlHttpRequest->CookedUrl.QueryStringLength = (USHORT)(cbBytesCopied - _pUlHttpRequest->CookedUrl.AbsPathLength);
  1229. }
  1230. else
  1231. {
  1232. if ( fResetQueryString )
  1233. {
  1234. _pUlHttpRequest->CookedUrl.pQueryString = NULL;
  1235. _pUlHttpRequest->CookedUrl.QueryStringLength = 0;
  1236. }
  1237. _pUlHttpRequest->CookedUrl.AbsPathLength = (USHORT) cbBytesCopied;
  1238. }
  1239. hr = strAbsPath.Copy(pszNewAbsPath);
  1240. if (FAILED(hr))
  1241. {
  1242. goto Finished;
  1243. }
  1244. //
  1245. // Need to patch up the Full Url.
  1246. //
  1247. BuildFullUrl( strAbsPath, &strFullUrl, FALSE);
  1248. hr = _HeaderBuffer.AllocateSpace( strFullUrl.QueryStr(),
  1249. strFullUrl.QueryCCH(),
  1250. &pszNewFullUrl );
  1251. if (FAILED(hr))
  1252. {
  1253. goto Finished;
  1254. }
  1255. _pUlHttpRequest->CookedUrl.pFullUrl = pszNewFullUrl;
  1256. _pUlHttpRequest->CookedUrl.FullUrlLength = (USHORT) strFullUrl.QueryCB();
  1257. Finished:
  1258. return hr;
  1259. }
  1260. HRESULT
  1261. W3_REQUEST::BuildISAPIHeaderLine(
  1262. CHAR * pszHeaderName,
  1263. DWORD cchHeaderName,
  1264. CHAR * pszHeaderValue,
  1265. DWORD cchHeaderValue,
  1266. STRA * pstrHeaderLine
  1267. )
  1268. /*++
  1269. Routine Description:
  1270. Private utility to build a header line as such:
  1271. pszHeaderName = "this-is-a-header", pszHeaderValue = "foobar"
  1272. PRODUCES
  1273. "HTTP_THIS_IS_A_HEADER:foobar\n"
  1274. Arguments:
  1275. pszHeaderName - Header name
  1276. cchHeaderName - Length of header name
  1277. pszHeaderValue - Header value
  1278. cchHeaderValue - Length of header value
  1279. pstrHeaderLine - Header line is appended
  1280. Return Value:
  1281. HRESULT
  1282. --*/
  1283. {
  1284. HRESULT hr;
  1285. CHAR * pszCursor;
  1286. DWORD currHeaderLength = pstrHeaderLine->QueryCCH();
  1287. //
  1288. // Convert header name "a-b-c" into "HTTP_A_B_C"
  1289. //
  1290. hr = pstrHeaderLine->Append( "HTTP_", 5 );
  1291. if ( FAILED( hr ) )
  1292. {
  1293. return hr;
  1294. }
  1295. hr = pstrHeaderLine->Append( pszHeaderName, cchHeaderName );
  1296. if ( FAILED( hr ) )
  1297. {
  1298. return hr;
  1299. }
  1300. //
  1301. // Convert - to _
  1302. //
  1303. pszCursor = strchr( pstrHeaderLine->QueryStr() + currHeaderLength + 5,
  1304. '-' );
  1305. while ( pszCursor != NULL )
  1306. {
  1307. *pszCursor++ = '_';
  1308. pszCursor = strchr( pszCursor, L'-' );
  1309. }
  1310. //
  1311. // Uppercase it
  1312. //
  1313. _strupr( pstrHeaderLine->QueryStr() + currHeaderLength + 5 );
  1314. //
  1315. // Now finish the header line by adding ":<header value>\n"
  1316. //
  1317. // Note that raw HTTP looks like ": <header value>", but earlier
  1318. // versions of IIS did not include the space, and there are
  1319. // legacy ISAPI's that depend on the space after the colon
  1320. // not being there.
  1321. //
  1322. hr = pstrHeaderLine->Append( ":", 1 );
  1323. if ( FAILED( hr ) )
  1324. {
  1325. return hr;
  1326. }
  1327. hr = pstrHeaderLine->Append( pszHeaderValue, cchHeaderValue );
  1328. if ( FAILED( hr ) )
  1329. {
  1330. return hr;
  1331. }
  1332. hr = pstrHeaderLine->Append( "\n", 1 );
  1333. if ( FAILED( hr ) )
  1334. {
  1335. return hr;
  1336. }
  1337. return NO_ERROR;
  1338. }
  1339. HRESULT
  1340. W3_REQUEST::BuildRawHeaderLine(
  1341. CHAR * pszHeaderName,
  1342. DWORD cchHeaderName,
  1343. CHAR * pszHeaderValue,
  1344. DWORD cchHeaderValue,
  1345. STRA * pstrHeaderLine
  1346. )
  1347. /*++
  1348. Routine Description:
  1349. Private utility to build a header line as such:
  1350. pszHeaderName = "this-is-a-header", pszHeaderValue = "foobar"
  1351. PRODUCES
  1352. this-is-a-header: foobar\r\n
  1353. Arguments:
  1354. pszHeaderName - Header name
  1355. cchHeaderName - Length of header name
  1356. pszHeaderValue - Header value
  1357. cchHeaderValue - Length of header value
  1358. pstrHeaderLine - Header line is appended
  1359. Return Value:
  1360. HRESULT
  1361. --*/
  1362. {
  1363. HRESULT hr;
  1364. CHAR * pszCursor;
  1365. hr = pstrHeaderLine->Append( pszHeaderName );
  1366. if ( FAILED( hr ) )
  1367. {
  1368. return hr;
  1369. }
  1370. //
  1371. // Now finish the header line by adding ": <header value>\n"
  1372. //
  1373. hr = pstrHeaderLine->Append( ": ", 2 );
  1374. if ( FAILED( hr ) )
  1375. {
  1376. return hr;
  1377. }
  1378. hr = pstrHeaderLine->Append( pszHeaderValue, cchHeaderValue );
  1379. if ( FAILED( hr ) )
  1380. {
  1381. return hr;
  1382. }
  1383. hr = pstrHeaderLine->Append( "\r\n" );
  1384. if ( FAILED( hr ) )
  1385. {
  1386. return hr;
  1387. }
  1388. return NO_ERROR;
  1389. }
  1390. HRESULT
  1391. W3_REQUEST::GetAllHeaders(
  1392. STRA * pstrHeaders,
  1393. BOOL fISAPIStyle
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. Get all headers in one string, delimited by \r\n
  1398. Arguments:
  1399. pstrHeaders - Filled with headers
  1400. fISAPIStyle -
  1401. If TRUE, format is: HTTP_CONTENT_LENGTH: 245\nHTTP_CONTENT_TYPE: t\n
  1402. If FALSE, format is: CONTENT-LENGTH: 245\r\nCONTENT-TYPE: t\r\n
  1403. Return Value:
  1404. HRESULT
  1405. --*/
  1406. {
  1407. HRESULT hr = NO_ERROR;
  1408. DWORD cCounter;
  1409. HTTP_KNOWN_HEADER * pKnownHeader;
  1410. CHAR * pszName;
  1411. DWORD cchName;
  1412. HTTP_UNKNOWN_HEADER * pUnknownHeader;
  1413. if ( pstrHeaders == NULL )
  1414. {
  1415. DBG_ASSERT( FALSE );
  1416. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1417. }
  1418. //
  1419. // Copy known headers
  1420. //
  1421. for ( cCounter = 0;
  1422. cCounter < HttpHeaderRequestMaximum;
  1423. cCounter++ )
  1424. {
  1425. pKnownHeader = &(_pUlHttpRequest->Headers.pKnownHeaders[ cCounter ]);
  1426. if ( pKnownHeader->RawValueLength != 0 )
  1427. {
  1428. pszName = REQUEST_HEADER_HASH::GetString( cCounter, &cchName );
  1429. if ( pszName == NULL )
  1430. {
  1431. DBG_ASSERT( FALSE );
  1432. return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  1433. }
  1434. if ( fISAPIStyle )
  1435. {
  1436. hr = BuildISAPIHeaderLine( pszName,
  1437. cchName,
  1438. pKnownHeader->pRawValue,
  1439. pKnownHeader->RawValueLength,
  1440. pstrHeaders );
  1441. }
  1442. else
  1443. {
  1444. hr = BuildRawHeaderLine( pszName,
  1445. cchName,
  1446. pKnownHeader->pRawValue,
  1447. pKnownHeader->RawValueLength,
  1448. pstrHeaders );
  1449. }
  1450. if ( FAILED( hr ) )
  1451. {
  1452. return hr;
  1453. }
  1454. }
  1455. }
  1456. //
  1457. // Copy unknown headers
  1458. //
  1459. for ( cCounter = 0;
  1460. cCounter < _pUlHttpRequest->Headers.UnknownHeaderCount;
  1461. cCounter++ )
  1462. {
  1463. pUnknownHeader = &(_pUlHttpRequest->Headers.pUnknownHeaders[ cCounter ]);
  1464. pszName = pUnknownHeader->pName;
  1465. cchName = pUnknownHeader->NameLength;
  1466. if ( fISAPIStyle )
  1467. {
  1468. hr = BuildISAPIHeaderLine( pszName,
  1469. cchName,
  1470. pUnknownHeader->pRawValue,
  1471. pUnknownHeader->RawValueLength,
  1472. pstrHeaders );
  1473. }
  1474. else
  1475. {
  1476. hr = BuildRawHeaderLine( pszName,
  1477. cchName,
  1478. pUnknownHeader->pRawValue,
  1479. pUnknownHeader->RawValueLength,
  1480. pstrHeaders );
  1481. }
  1482. if ( FAILED( hr ) )
  1483. {
  1484. return hr;
  1485. }
  1486. }
  1487. return NO_ERROR;
  1488. }
  1489. HRESULT
  1490. W3_REQUEST::CloneRequest(
  1491. DWORD dwCloneFlags,
  1492. W3_REQUEST ** ppRequest
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. Clone request. Used to setup a child request to execute
  1497. Arguments:
  1498. dwCloneFlags - Flags controlling how much of the current request to clone.
  1499. Without any flag, we will copy only the bare minimum
  1500. W3_REQUEST_CLONE_BASICS - clone URL/querystring/Verb
  1501. W3_REQUEST_CLONE_HEADERS - clone request headers
  1502. W3_REQUEST_CLONE_ENTITY - clone the entity body
  1503. W3_REQUEST_CLONE_NO_PRECONDITION - remove range/if-*
  1504. W3_REQUEST_CLONE_NO_DAV - remove DAV requests
  1505. ppRequest - Set to point to a new W3_REQUEST on success
  1506. Return Value:
  1507. HRESULT
  1508. --*/
  1509. {
  1510. W3_CLONE_REQUEST * pCloneRequest = NULL;
  1511. HRESULT hr = NO_ERROR;
  1512. if ( ppRequest == NULL )
  1513. {
  1514. DBG_ASSERT( FALSE );
  1515. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1516. }
  1517. *ppRequest = NULL;
  1518. //
  1519. // Allocate a new cloned request
  1520. //
  1521. pCloneRequest = new W3_CLONE_REQUEST();
  1522. if ( pCloneRequest == NULL )
  1523. {
  1524. hr = HRESULT_FROM_WIN32( GetLastError() );
  1525. goto Finished;
  1526. }
  1527. //
  1528. // Copy the bare minimum
  1529. //
  1530. hr = pCloneRequest->CopyMinimum( _pUlHttpRequest );
  1531. if ( FAILED( hr ) )
  1532. {
  1533. goto Finished;
  1534. }
  1535. //
  1536. // Should we copy the request basics (URL/querystring/Verb)?
  1537. //
  1538. if ( dwCloneFlags & W3_REQUEST_CLONE_BASICS )
  1539. {
  1540. hr = pCloneRequest->CopyBasics( _pUlHttpRequest );
  1541. }
  1542. else
  1543. {
  1544. hr = pCloneRequest->CopyBasics( NULL );
  1545. }
  1546. if ( FAILED( hr ) )
  1547. {
  1548. goto Finished;
  1549. }
  1550. //
  1551. // Should we copy the headers?
  1552. //
  1553. if ( dwCloneFlags & W3_REQUEST_CLONE_HEADERS )
  1554. {
  1555. hr = pCloneRequest->CopyHeaders( _pUlHttpRequest );
  1556. }
  1557. else
  1558. {
  1559. hr = pCloneRequest->CopyHeaders( NULL );
  1560. }
  1561. if ( FAILED( hr ) )
  1562. {
  1563. goto Finished;
  1564. }
  1565. //
  1566. // Should we also reference the parent's entity body
  1567. //
  1568. if ( dwCloneFlags & W3_REQUEST_CLONE_ENTITY )
  1569. {
  1570. hr = pCloneRequest->CopyEntity( _pUlHttpRequest );
  1571. }
  1572. else
  1573. {
  1574. hr = pCloneRequest->CopyEntity( NULL );
  1575. }
  1576. if ( FAILED( hr ) )
  1577. {
  1578. goto Finished;
  1579. }
  1580. //
  1581. // Remove conditionals if requested
  1582. //
  1583. if ( dwCloneFlags & W3_REQUEST_CLONE_NO_PRECONDITION )
  1584. {
  1585. pCloneRequest->RemoveConditionals();
  1586. }
  1587. //
  1588. // Remove DAV'ness if requested
  1589. //
  1590. if ( dwCloneFlags & W3_REQUEST_CLONE_NO_DAV )
  1591. {
  1592. pCloneRequest->RemoveDav();
  1593. }
  1594. *ppRequest = pCloneRequest;
  1595. Finished:
  1596. if ( FAILED( hr ) )
  1597. {
  1598. if ( pCloneRequest != NULL )
  1599. {
  1600. delete pCloneRequest;
  1601. pCloneRequest = NULL;
  1602. }
  1603. }
  1604. return hr;
  1605. }
  1606. //static
  1607. HRESULT
  1608. W3_REQUEST::Initialize(
  1609. VOID
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. Global initalization for utilities used by W3_REQUEST object
  1614. Arguments:
  1615. None
  1616. Return Value:
  1617. HRESULT
  1618. --*/
  1619. {
  1620. CHAR achName[ MAX_PATH + 1 ];
  1621. INT err;
  1622. HRESULT hr;
  1623. //
  1624. // Get the host name for use in remote/local determination
  1625. //
  1626. err = gethostname( achName, sizeof( achName ) );
  1627. if ( err != 0 )
  1628. {
  1629. hr = HRESULT_FROM_WIN32( WSAGetLastError() );
  1630. DBGPRINTF(( DBG_CONTEXT,
  1631. "Error getting host name. hr = %x\n",
  1632. hr ));
  1633. return hr;
  1634. }
  1635. sm_pHostEnt = gethostbyname( achName );
  1636. if ( sm_pHostEnt == NULL )
  1637. {
  1638. hr = HRESULT_FROM_WIN32( WSAGetLastError() );
  1639. DBGPRINTF(( DBG_CONTEXT,
  1640. "Error getting host. hr = %x\n",
  1641. hr ));
  1642. return hr;
  1643. }
  1644. hr = REQUEST_HEADER_HASH::Initialize();
  1645. if ( FAILED( hr ) )
  1646. {
  1647. return hr;
  1648. }
  1649. hr = METHOD_HASH::Initialize();
  1650. if ( FAILED( hr ) )
  1651. {
  1652. return hr;
  1653. }
  1654. hr = W3_CLONE_REQUEST::Initialize();
  1655. if ( FAILED( hr ) )
  1656. {
  1657. REQUEST_HEADER_HASH::Terminate();
  1658. return hr;
  1659. }
  1660. return NO_ERROR;
  1661. }
  1662. //static
  1663. VOID
  1664. W3_REQUEST::Terminate(
  1665. VOID
  1666. )
  1667. {
  1668. W3_CLONE_REQUEST::Terminate();
  1669. REQUEST_HEADER_HASH::Terminate();
  1670. METHOD_HASH::Terminate();
  1671. }
  1672. HRESULT
  1673. W3_CLONE_REQUEST::CopyEntity(
  1674. HTTP_REQUEST * pRequestToClone
  1675. )
  1676. /*++
  1677. Routine Description:
  1678. Reference the parents entity body if required
  1679. Arguments:
  1680. pRequestToClone - UL_HTTP_REQUEST to clone. NULL if we shouldn't clone
  1681. Return Value:
  1682. HRESULT
  1683. --*/
  1684. {
  1685. if ( pRequestToClone == NULL )
  1686. {
  1687. _ulHttpRequest.MoreEntityBodyExists = FALSE;
  1688. _ulHttpRequest.EntityChunkCount = 0;
  1689. _ulHttpRequest.pEntityChunks = NULL;
  1690. }
  1691. else
  1692. {
  1693. _ulHttpRequest.MoreEntityBodyExists = pRequestToClone->MoreEntityBodyExists;
  1694. _ulHttpRequest.EntityChunkCount = pRequestToClone->EntityChunkCount;
  1695. _ulHttpRequest.pEntityChunks = pRequestToClone->pEntityChunks;
  1696. }
  1697. return S_OK;
  1698. }
  1699. HRESULT
  1700. W3_CLONE_REQUEST::CopyBasics(
  1701. HTTP_REQUEST * pRequestToClone
  1702. )
  1703. /*++
  1704. Routine Description:
  1705. Copy the URL/query-string/Verb if required
  1706. Arguments:
  1707. pRequestToClone - HTTP_REQUEST to clone. NULL if we shouldn't clone
  1708. Return Value:
  1709. HRESULT
  1710. --*/
  1711. {
  1712. if ( pRequestToClone == NULL )
  1713. {
  1714. _ulHttpRequest.Verb = HttpVerbUnparsed;
  1715. _ulHttpRequest.UnknownVerbLength = 0;
  1716. _ulHttpRequest.pUnknownVerb = NULL;
  1717. _ulHttpRequest.RawUrlLength = 0;
  1718. _ulHttpRequest.pRawUrl = NULL;
  1719. _ulHttpRequest.CookedUrl.FullUrlLength = 0;
  1720. _ulHttpRequest.CookedUrl.pFullUrl = NULL;
  1721. _ulHttpRequest.CookedUrl.HostLength = 0;
  1722. _ulHttpRequest.CookedUrl.pHost = NULL;
  1723. _ulHttpRequest.CookedUrl.AbsPathLength = 0;
  1724. _ulHttpRequest.CookedUrl.pAbsPath = NULL;
  1725. _ulHttpRequest.CookedUrl.QueryStringLength = 0;
  1726. _ulHttpRequest.CookedUrl.pQueryString = NULL;
  1727. }
  1728. else
  1729. {
  1730. _ulHttpRequest.Verb = pRequestToClone->Verb;
  1731. _ulHttpRequest.UnknownVerbLength = pRequestToClone->UnknownVerbLength;
  1732. _ulHttpRequest.pUnknownVerb = pRequestToClone->pUnknownVerb;
  1733. _ulHttpRequest.RawUrlLength = pRequestToClone->RawUrlLength;
  1734. _ulHttpRequest.pRawUrl = pRequestToClone->pRawUrl;
  1735. _ulHttpRequest.CookedUrl.FullUrlLength = pRequestToClone->CookedUrl.FullUrlLength;
  1736. _ulHttpRequest.CookedUrl.pFullUrl = pRequestToClone->CookedUrl.pFullUrl;
  1737. _ulHttpRequest.CookedUrl.HostLength = pRequestToClone->CookedUrl.HostLength;
  1738. _ulHttpRequest.CookedUrl.pHost = pRequestToClone->CookedUrl.pHost;
  1739. _ulHttpRequest.CookedUrl.AbsPathLength = pRequestToClone->CookedUrl.AbsPathLength;
  1740. _ulHttpRequest.CookedUrl.pAbsPath = pRequestToClone->CookedUrl.pAbsPath;
  1741. _ulHttpRequest.CookedUrl.QueryStringLength = pRequestToClone->CookedUrl.QueryStringLength;
  1742. _ulHttpRequest.CookedUrl.pQueryString = pRequestToClone->CookedUrl.pQueryString;
  1743. }
  1744. return S_OK;
  1745. }
  1746. HRESULT
  1747. W3_CLONE_REQUEST::CopyMinimum(
  1748. HTTP_REQUEST * pRequestToClone
  1749. )
  1750. /*++
  1751. Routine Description:
  1752. Copies the bare minimum from the clonee. Bare minimums includes
  1753. remote/local port/address, version, etc.
  1754. Arguments:
  1755. pRequestToClone - UL_HTTP_REQUEST to clone
  1756. Return Value:
  1757. HRESULT
  1758. --*/
  1759. {
  1760. if ( pRequestToClone == NULL )
  1761. {
  1762. DBG_ASSERT( FALSE );
  1763. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1764. }
  1765. //
  1766. // Miscellaneous UL goo
  1767. //
  1768. _ulHttpRequest.ConnectionId = pRequestToClone->ConnectionId;
  1769. _ulHttpRequest.RequestId = pRequestToClone->RequestId;
  1770. _ulHttpRequest.UrlContext = pRequestToClone->UrlContext;
  1771. _ulHttpRequest.Version = pRequestToClone->Version;
  1772. //
  1773. // Local/Remote address
  1774. //
  1775. _ulHttpRequest.Address.RemoteAddressLength = pRequestToClone->Address.RemoteAddressLength;
  1776. _ulHttpRequest.Address.RemoteAddressType = pRequestToClone->Address.RemoteAddressType;
  1777. _ulHttpRequest.Address.LocalAddressLength = pRequestToClone->Address.LocalAddressLength;
  1778. _ulHttpRequest.Address.LocalAddressType = pRequestToClone->Address.LocalAddressType;
  1779. _ulHttpRequest.Address.pRemoteAddress = pRequestToClone->Address.pRemoteAddress;
  1780. _ulHttpRequest.Address.pLocalAddress = pRequestToClone->Address.pLocalAddress;
  1781. //
  1782. // Other stuff
  1783. //
  1784. _ulHttpRequest.RawConnectionId = pRequestToClone->RawConnectionId;
  1785. _ulHttpRequest.pSslInfo = pRequestToClone->pSslInfo;
  1786. return NO_ERROR;
  1787. }
  1788. HRESULT
  1789. W3_CLONE_REQUEST::CopyHeaders(
  1790. HTTP_REQUEST * pRequestToClone
  1791. )
  1792. /*++
  1793. Routine Description:
  1794. Copies request headers from pRequestToClone into the current cloned
  1795. request
  1796. Arguments:
  1797. pRequestToClone - HTTP_REQUEST to clone, NULL if there should be no
  1798. headers
  1799. Return Value:
  1800. HRESULT
  1801. --*/
  1802. {
  1803. DWORD cUnknownHeaders;
  1804. if ( pRequestToClone == NULL )
  1805. {
  1806. //
  1807. // No headers.
  1808. //
  1809. ZeroMemory( &( _ulHttpRequest.Headers ),
  1810. sizeof( _ulHttpRequest.Headers ) );
  1811. }
  1812. else
  1813. {
  1814. //
  1815. // Copy all the headers
  1816. //
  1817. //
  1818. // Start with the known headers. Note that we can just copy
  1819. // the Headers member directly. The memory being referenced by
  1820. // the pointers are guaranteed to be around for the life of this
  1821. // request. (the memory is either off the UL_NATIVE_REQUEST or
  1822. // it is off a CHUNK_BUFFER from the main parent request)
  1823. //
  1824. memcpy( _ulHttpRequest.Headers.pKnownHeaders,
  1825. pRequestToClone->Headers.pKnownHeaders,
  1826. sizeof( _ulHttpRequest.Headers.pKnownHeaders ) );
  1827. //
  1828. // Copy the unknown headers. For this case, we will have to
  1829. // allocate our own buffer since the unknown header array can be
  1830. // resized. But as before, the memory referenced by the
  1831. // unknown headers is OK to reference again.
  1832. //
  1833. cUnknownHeaders = pRequestToClone->Headers.UnknownHeaderCount;
  1834. if ( cUnknownHeaders > 0 )
  1835. {
  1836. _pExtraUnknown = (HTTP_UNKNOWN_HEADER*) LocalAlloc(
  1837. LPTR,
  1838. sizeof( HTTP_UNKNOWN_HEADER)*
  1839. cUnknownHeaders );
  1840. if ( _pExtraUnknown == NULL )
  1841. {
  1842. return HRESULT_FROM_WIN32( GetLastError() );
  1843. }
  1844. memcpy( _pExtraUnknown,
  1845. pRequestToClone->Headers.pUnknownHeaders,
  1846. cUnknownHeaders * sizeof( HTTP_UNKNOWN_HEADER ) );
  1847. }
  1848. _ulHttpRequest.Headers.UnknownHeaderCount = cUnknownHeaders;
  1849. _ulHttpRequest.Headers.pUnknownHeaders = _pExtraUnknown;
  1850. }
  1851. return NO_ERROR;
  1852. }
  1853. VOID
  1854. W3_CLONE_REQUEST::RemoveConditionals(
  1855. VOID
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. Remove conditional/range headers from request. Used to allow a custom
  1860. error URL to work correctly
  1861. Arguments:
  1862. None
  1863. Return Value:
  1864. None
  1865. --*/
  1866. {
  1867. HTTP_REQUEST_HEADERS * pHeaders;
  1868. pHeaders = &(_pUlHttpRequest->Headers);
  1869. //
  1870. // Remove Range:
  1871. //
  1872. pHeaders->pKnownHeaders[ HttpHeaderRange ].pRawValue = NULL;
  1873. pHeaders->pKnownHeaders[ HttpHeaderRange ].RawValueLength = 0;
  1874. //
  1875. // Remove If-Modified-Since:
  1876. //
  1877. pHeaders->pKnownHeaders[ HttpHeaderIfModifiedSince ].pRawValue = NULL;
  1878. pHeaders->pKnownHeaders[ HttpHeaderIfModifiedSince ].RawValueLength = 0;
  1879. //
  1880. // Remove If-Match:
  1881. //
  1882. pHeaders->pKnownHeaders[ HttpHeaderIfMatch ].pRawValue = NULL;
  1883. pHeaders->pKnownHeaders[ HttpHeaderIfMatch ].RawValueLength = 0;
  1884. //
  1885. // Remove If-Unmodifed-Since:
  1886. //
  1887. pHeaders->pKnownHeaders[ HttpHeaderIfUnmodifiedSince ].pRawValue = NULL;
  1888. pHeaders->pKnownHeaders[ HttpHeaderIfUnmodifiedSince ].RawValueLength = 0;
  1889. //
  1890. // Remove If-Range:
  1891. //
  1892. pHeaders->pKnownHeaders[ HttpHeaderIfRange ].pRawValue = NULL;
  1893. pHeaders->pKnownHeaders[ HttpHeaderIfRange ].RawValueLength = 0;
  1894. //
  1895. // Remove If-None-Match:
  1896. //
  1897. pHeaders->pKnownHeaders[ HttpHeaderIfNoneMatch ].pRawValue = NULL;
  1898. pHeaders->pKnownHeaders[ HttpHeaderIfNoneMatch ].RawValueLength = 0;
  1899. }
  1900. //static
  1901. HRESULT
  1902. W3_CLONE_REQUEST::Initialize(
  1903. VOID
  1904. )
  1905. /*++
  1906. Routine Description:
  1907. Initialize clone request lookaside
  1908. Arguments:
  1909. None
  1910. Return Value:
  1911. HRESULT
  1912. --*/
  1913. {
  1914. ALLOC_CACHE_CONFIGURATION acConfig;
  1915. DBG_ASSERT( sm_pachCloneRequests == NULL );
  1916. //
  1917. // Setup allocation lookaside
  1918. //
  1919. acConfig.nConcurrency = 1;
  1920. acConfig.nThreshold = 100;
  1921. acConfig.cbSize = sizeof( W3_CLONE_REQUEST );
  1922. sm_pachCloneRequests = new ALLOC_CACHE_HANDLER( "W3_CLONE_REQUEST",
  1923. &acConfig );
  1924. if ( sm_pachCloneRequests == NULL )
  1925. {
  1926. return HRESULT_FROM_WIN32( GetLastError() );
  1927. }
  1928. return NO_ERROR;
  1929. }
  1930. //static
  1931. VOID
  1932. W3_CLONE_REQUEST::Terminate(
  1933. VOID
  1934. )
  1935. /*++
  1936. Routine Description:
  1937. Terminate clone request lookaside
  1938. Arguments:
  1939. None
  1940. Return Value:
  1941. None
  1942. --*/
  1943. {
  1944. if ( sm_pachCloneRequests != NULL )
  1945. {
  1946. delete sm_pachCloneRequests;
  1947. sm_pachCloneRequests = NULL;
  1948. }
  1949. }
  1950. HRESULT
  1951. W3_REQUEST::PreloadEntityBody(
  1952. W3_CONTEXT *pW3Context,
  1953. BOOL *pfComplete
  1954. )
  1955. /*++
  1956. Routine Description:
  1957. Preload entity body for this request if appropriate
  1958. Arguments:
  1959. cbConfiguredReadAhead - Amount to preload
  1960. pfComplete - Set to TRUE if preload is complete
  1961. Return Value:
  1962. HRESULT
  1963. --*/
  1964. {
  1965. DWORD cbConfiguredReadAhead;
  1966. DWORD cbAvailableAlready = 0;
  1967. PVOID pbAvailableAlready = NULL;
  1968. DWORD cbAmountToPreload = 0;
  1969. HRESULT hr;
  1970. W3_METADATA *pMetadata = pW3Context->QueryUrlContext()->QueryMetaData();
  1971. cbConfiguredReadAhead = pMetadata->QueryEntityReadAhead();
  1972. *pfComplete = FALSE;
  1973. //
  1974. // How much entity do we already have available to us? If it is more
  1975. // than the preload size then we are finished
  1976. //
  1977. pbAvailableAlready = QueryEntityBody();
  1978. cbAvailableAlready = QueryAvailableBytes();
  1979. if ( cbAvailableAlready >= cbConfiguredReadAhead )
  1980. {
  1981. *pfComplete = TRUE;
  1982. return S_OK;
  1983. }
  1984. //
  1985. // OK. We don't have the configured preload-size number of bytes
  1986. // currently available.
  1987. //
  1988. // Do we know how many bytes of entity are available from UL still.
  1989. //
  1990. cbAmountToPreload = pW3Context->QueryRemainingEntityFromUl();
  1991. if ( cbAmountToPreload == INFINITE )
  1992. {
  1993. //
  1994. // Must be a chunked request. Cap at configured read ahead
  1995. //
  1996. cbAmountToPreload = cbConfiguredReadAhead;
  1997. }
  1998. else if ( cbAmountToPreload == 0 )
  1999. {
  2000. //
  2001. // There is no more data available from UL.
  2002. //
  2003. *pfComplete = TRUE;
  2004. return S_OK;
  2005. }
  2006. else
  2007. {
  2008. //
  2009. // There is still data to be read from UL
  2010. //
  2011. cbAmountToPreload += cbAvailableAlready;
  2012. cbAmountToPreload = min( cbAmountToPreload, cbConfiguredReadAhead );
  2013. }
  2014. //
  2015. // Allocate the buffer
  2016. //
  2017. if ( !_buffEntityBodyPreload.Resize( cbAmountToPreload ) )
  2018. {
  2019. return HRESULT_FROM_WIN32( GetLastError() );
  2020. }
  2021. //
  2022. // Copy any data already available to us
  2023. //
  2024. if ( cbAvailableAlready > 0 &&
  2025. pbAvailableAlready != _buffEntityBodyPreload.QueryPtr())
  2026. {
  2027. DBG_ASSERT( pbAvailableAlready != NULL );
  2028. memcpy( _buffEntityBodyPreload.QueryPtr(),
  2029. pbAvailableAlready,
  2030. cbAvailableAlready );
  2031. }
  2032. //
  2033. // Now read the read from UL asychronously
  2034. //
  2035. hr = pW3Context->ReceiveEntity( W3_FLAG_ASYNC,
  2036. (PBYTE) _buffEntityBodyPreload.QueryPtr() + cbAvailableAlready,
  2037. cbAmountToPreload - cbAvailableAlready,
  2038. NULL );
  2039. if ( FAILED( hr ) )
  2040. {
  2041. //
  2042. // In the chunked case, we do not know how many bytes there were so
  2043. // we can hit EOF. However, if the client sent content-length, then
  2044. // it is an error
  2045. //
  2046. if (hr == HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) &&
  2047. pW3Context->QueryRemainingEntityFromUl() == INFINITE)
  2048. {
  2049. pW3Context->SetRemainingEntityFromUl(0);
  2050. *pfComplete = TRUE;
  2051. return S_OK;
  2052. }
  2053. return hr;
  2054. }
  2055. *pfComplete = FALSE;
  2056. return S_OK;
  2057. }
  2058. HRESULT W3_REQUEST::PreloadCompletion(W3_CONTEXT *pW3Context,
  2059. DWORD cbRead,
  2060. DWORD dwStatus,
  2061. BOOL *pfComplete)
  2062. {
  2063. if ( dwStatus )
  2064. {
  2065. //
  2066. // In the chunked case, we do not know how many bytes there were so
  2067. // we can hit EOF. However, if the client sent content-length, then
  2068. // it is an error
  2069. //
  2070. if (dwStatus == ERROR_HANDLE_EOF &&
  2071. pW3Context->QueryRemainingEntityFromUl() == INFINITE)
  2072. {
  2073. pW3Context->SetRemainingEntityFromUl(0);
  2074. *pfComplete = TRUE;
  2075. return S_OK;
  2076. }
  2077. return HRESULT_FROM_WIN32(dwStatus);
  2078. }
  2079. SetNewPreloadedEntityBody(_buffEntityBodyPreload.QueryPtr(),
  2080. QueryAvailableBytes() + cbRead);
  2081. return PreloadEntityBody(pW3Context, pfComplete);
  2082. }