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.

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