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.

2825 lines
70 KiB

  1. #include <wininetp.h>
  2. #include <perfdiag.hxx>
  3. #include "httpp.h"
  4. #include <wininetp.h>
  5. #define DATE_AND_TIME_STRING_BUFFER_LENGTH 128
  6. PRIVATE
  7. BOOL
  8. FMatchList(
  9. LPSTR *lplpList,
  10. DWORD cListLen,
  11. HEADER_STRING *lpHeader,
  12. LPSTR lpBase
  13. )
  14. {
  15. DWORD i;
  16. for (i=0; i < cListLen; ++i) {
  17. if (!lpHeader->Strnicmp(lpBase, lplpList[i], strlen(lplpList[i]))) {
  18. return (TRUE);
  19. }
  20. }
  21. return(FALSE);
  22. }
  23. DWORD
  24. FASTCALL
  25. CalculateHashNoCase(
  26. IN LPCSTR lpszString,
  27. IN DWORD dwStringLength
  28. )
  29. /*++
  30. Routine Description:
  31. Calculate a case-insensitive hash number given a string. Assumes input is
  32. 7-bit ASCII
  33. Arguments:
  34. lpszString - string to hash
  35. dwStringLength - length of lpszString, or -1 if we need to calculate
  36. Return Value:
  37. DWORD - a generated hash value
  38. --*/
  39. {
  40. DWORD dwHash = HEADER_HASH_SEED;
  41. while (dwStringLength != 0) {
  42. CHAR ch = *lpszString;
  43. if ((ch >= 'A') && (ch <= 'Z')) {
  44. ch = MAKE_LOWER(ch);
  45. }
  46. dwHash += (DWORD)(dwHash << 5) + ch; /*+ *pszName++;*/
  47. ++lpszString;
  48. --dwStringLength;
  49. }
  50. return dwHash;
  51. }
  52. //
  53. // methods
  54. //
  55. DWORD
  56. HTTP_HEADERS::AllocateHeaders(
  57. IN DWORD dwNumberOfHeaders
  58. )
  59. /*++
  60. Routine Description:
  61. Allocates or grows the array of header pointers (HEADER_STRING objects)
  62. Arguments:
  63. dwNumberOfHeaders - number of additional header slots to create
  64. Return Value:
  65. DWORD
  66. Success - ERROR_SUCCESS
  67. Failure - ERROR_NOT_ENOUGH_MEMORY
  68. --*/
  69. {
  70. DEBUG_ENTER((DBG_HTTP,
  71. Dword,
  72. "AllocateHeaders",
  73. "%d",
  74. dwNumberOfHeaders
  75. ));
  76. PERF_ENTER(AllocateHeaders);
  77. //
  78. // we really need to be able to realloc an array of HEADER_STRING objects
  79. // (see below)
  80. //
  81. DWORD error;
  82. DWORD slots = _TotalSlots;
  83. if (dwNumberOfHeaders == 0)
  84. {
  85. INET_ASSERT(0); // AllocateHeaders() asked to allocate 0 headers.. a mistake in the calling code.
  86. error = ERROR_SUCCESS;
  87. goto quit;
  88. }
  89. if (_TotalSlots + dwNumberOfHeaders > (INVALID_HEADER_INDEX-1))
  90. {
  91. // We may end up allocating fewer than we were asked for, but we'll always allocate at least one.
  92. dwNumberOfHeaders = (INVALID_HEADER_INDEX-1)-_TotalSlots;
  93. }
  94. if ( dwNumberOfHeaders == 0)
  95. {
  96. error = ERROR_WINHTTP_HEADER_COUNT_EXCEEDED;
  97. goto quit;
  98. }
  99. _lpHeaders = (HEADER_STRING *)ResizeBuffer((HLOCAL)_lpHeaders,
  100. (_TotalSlots + dwNumberOfHeaders)
  101. * sizeof(HEADER_STRING),
  102. FALSE // not moveable
  103. );
  104. if (_lpHeaders != NULL) {
  105. _NextOpenSlot = _TotalSlots;
  106. _TotalSlots += dwNumberOfHeaders;
  107. _FreeSlots += dwNumberOfHeaders;
  108. //
  109. // this is slightly ugly, but it seems there's no easy C++ way to
  110. // do this - we need to be able to realloc() an array of objects
  111. // created by new(), but so far, it can't be done
  112. //
  113. for (; slots < _TotalSlots; ++slots) {
  114. _lpHeaders[slots].Clear();
  115. }
  116. error = ERROR_SUCCESS;
  117. } else {
  118. INET_ASSERT(FALSE);
  119. _NextOpenSlot = 0;
  120. _TotalSlots = 0;
  121. _FreeSlots = 0;
  122. error = ERROR_NOT_ENOUGH_MEMORY;
  123. }
  124. quit:
  125. INET_ASSERT(_FreeSlots <= _TotalSlots);
  126. PERF_LEAVE(AllocateHeaders);
  127. DEBUG_LEAVE(error);
  128. return error;
  129. }
  130. VOID
  131. HTTP_HEADERS::FreeHeaders(
  132. VOID
  133. )
  134. /*++
  135. Routine Description:
  136. Free the headers strings and the headers array
  137. Arguments:
  138. None.
  139. Return Value:
  140. None.
  141. --*/
  142. {
  143. DEBUG_ENTER((DBG_HTTP,
  144. None,
  145. "FreeHeaders",
  146. NULL
  147. ));
  148. if (!LockHeaders())
  149. {
  150. goto quit;
  151. }
  152. //
  153. // free up each individual entry (free string buffers)
  154. //
  155. for (DWORD i = 0; i < _TotalSlots; ++i) {
  156. _lpHeaders[i] = (LPSTR)NULL;
  157. }
  158. //
  159. // followed by the array itself
  160. //
  161. if (_lpHeaders) {
  162. _lpHeaders = (HEADER_STRING *)FREE_MEMORY((HLOCAL)_lpHeaders);
  163. INET_ASSERT(_lpHeaders == NULL);
  164. }
  165. _TotalSlots = 0;
  166. _FreeSlots = 0;
  167. _HeadersLength = 0;
  168. _lpszVerb = NULL;
  169. _dwVerbLength = 0;
  170. _lpszObjectName = NULL;
  171. _dwObjectNameLength = 0;
  172. _lpszVersion = NULL;
  173. _dwVersionLength = 0;
  174. UnlockHeaders();
  175. quit:
  176. DEBUG_LEAVE(0);
  177. }
  178. DWORD
  179. HTTP_HEADERS::CopyHeaders(
  180. IN OUT LPSTR * lpBuffer,
  181. IN LPSTR lpszObjectName,
  182. IN DWORD dwObjectNameLength
  183. )
  184. /*++
  185. Routine Description:
  186. Copy the headers to the caller's buffer. Each header is terminated by CR-LF.
  187. This method is called to convert the request headers list to a buffer that
  188. we can send to the server
  189. N.B. This function MUST be called with the headers already locked
  190. Arguments:
  191. lpBuffer - pointer to pointer to buffer where headers are
  192. written. We update the pointer
  193. lpszObjectName - optional object name
  194. dwObjectNameLength - optional object name length
  195. Return Value:
  196. DWORD
  197. Success - ERROR_SUCCESS
  198. Failure - ERROR_NOT_ENOUGH_MEMORY
  199. Ran out of memory while trying to synchronize src data access
  200. --*/
  201. {
  202. DEBUG_ENTER((DBG_HTTP,
  203. None,
  204. "CopyHeaders",
  205. "%#x, %#x [%q], %d",
  206. lpBuffer,
  207. lpszObjectName,
  208. lpszObjectName,
  209. dwObjectNameLength
  210. ));
  211. DWORD dwError = ERROR_SUCCESS;
  212. if (!LockHeaders())
  213. {
  214. dwError = ERROR_NOT_ENOUGH_MEMORY;
  215. goto quit;
  216. }
  217. DWORD i = 0;
  218. if (lpszObjectName != NULL) {
  219. memcpy(*lpBuffer, _lpszVerb, _dwVerbLength);
  220. *lpBuffer += _dwVerbLength;
  221. *(*lpBuffer)++ = ' ';
  222. memcpy(*lpBuffer, lpszObjectName, dwObjectNameLength);
  223. *lpBuffer += dwObjectNameLength;
  224. *(*lpBuffer)++ = ' ';
  225. memcpy(*lpBuffer, _lpszVersion, _dwVersionLength);
  226. *lpBuffer += _dwVersionLength;
  227. *(*lpBuffer)++ = '\r';
  228. *(*lpBuffer)++ = '\n';
  229. i = 1;
  230. }
  231. for (; i < _TotalSlots; ++i) {
  232. if (_lpHeaders[i].HaveString()) {
  233. _lpHeaders[i].CopyTo(*lpBuffer);
  234. *lpBuffer += _lpHeaders[i].StringLength();
  235. *(*lpBuffer)++ = '\r';
  236. *(*lpBuffer)++ = '\n';
  237. }
  238. }
  239. UnlockHeaders();
  240. quit:
  241. DEBUG_LEAVE(dwError);
  242. return dwError;
  243. }
  244. HEADER_STRING *
  245. FASTCALL
  246. HTTP_HEADERS::FindFreeSlot(
  247. DWORD* piSlot
  248. )
  249. /*++
  250. Routine Description:
  251. Finds the next free slot in the headers list, or adds some new slots
  252. N.B. This function MUST be called with the headers already locked
  253. Arguments:
  254. piSlot: returns index of slot found
  255. Return Value:
  256. HEADER_STRING * - pointer to next free slot
  257. --*/
  258. {
  259. DEBUG_ENTER((DBG_HTTP,
  260. Pointer,
  261. "FindFreeSlot",
  262. NULL
  263. ));
  264. PERF_ENTER(FindFreeSlot);
  265. DWORD i;
  266. DWORD error;
  267. HEADER_STRING * header = NULL;
  268. //
  269. // if there are no free slots, allocate some more
  270. //
  271. if (_FreeSlots == 0) {
  272. i = _TotalSlots;
  273. error = AllocateHeaders(HEADERS_INCREMENT);
  274. } else {
  275. i = 0;
  276. error = ERROR_SUCCESS;
  277. if (!_lpHeaders[_NextOpenSlot].HaveString())
  278. {
  279. --_FreeSlots;
  280. header = &_lpHeaders[_NextOpenSlot];
  281. *piSlot = _NextOpenSlot;
  282. _NextOpenSlot = (_NextOpenSlot == (_TotalSlots-1)) ? (_TotalSlots-1) : _NextOpenSlot++;
  283. goto quit;
  284. }
  285. }
  286. if (error == ERROR_SUCCESS) {
  287. for (; i < _TotalSlots; ++i) {
  288. if (!_lpHeaders[i].HaveString()) {
  289. --_FreeSlots;
  290. header = &_lpHeaders[i];
  291. *piSlot = i;
  292. _NextOpenSlot = (i == (_TotalSlots-1)) ? (_TotalSlots-1) : (i+1);
  293. break;
  294. }
  295. }
  296. if (header == NULL) {
  297. //
  298. // we would have just allocated extra slots if we didn't have
  299. // any, so we shouldn't be here
  300. //
  301. INET_ASSERT(FALSE);
  302. error = ERROR_WINHTTP_INTERNAL_ERROR;
  303. }
  304. }
  305. quit:
  306. _Error = error;
  307. PERF_LEAVE(FindFreeSlot);
  308. DEBUG_LEAVE(header);
  309. return header;
  310. }
  311. VOID
  312. HTTP_HEADERS::ShrinkHeader(
  313. IN LPBYTE pbBase,
  314. IN DWORD iSlot,
  315. IN DWORD dwOldQueryIndex,
  316. IN DWORD dwNewQueryIndex,
  317. IN DWORD cbNewSize
  318. )
  319. /*++
  320. Routine Description:
  321. Low level function that does a surgical replace of one header with another.
  322. This code updates internal structures such as bKnownHeaders and the stored
  323. hash value for the new Header.
  324. N.B. This function MUST be called with the headers already locked
  325. Arguments:
  326. Return Value:
  327. None.
  328. --*/
  329. {
  330. HEADER_STRING* pHeader = _lpHeaders + iSlot;
  331. UNREFERENCED_PARAMETER(pbBase);
  332. INET_ASSERT(_bKnownHeaders[dwOldQueryIndex] == (BYTE) iSlot ||
  333. dwNewQueryIndex == dwOldQueryIndex );
  334. //
  335. // Swap in the new header. Update Length, Hash, and its cached position
  336. // in the known header array.
  337. //
  338. _bKnownHeaders[dwOldQueryIndex] = INVALID_HEADER_INDEX;
  339. _bKnownHeaders[dwNewQueryIndex] = (BYTE) iSlot;
  340. pHeader->SetLength (cbNewSize);
  341. pHeader->SetHash (GlobalKnownHeaders[dwNewQueryIndex].HashVal);
  342. }
  343. DWORD
  344. inline
  345. HTTP_HEADERS::SlowFind(
  346. IN LPSTR lpBase,
  347. IN LPCSTR lpszHeaderName,
  348. IN DWORD dwHeaderNameLength,
  349. IN DWORD dwIndex,
  350. IN DWORD dwHash,
  351. OUT DWORD *lpdwQueryIndex,
  352. OUT BYTE **lplpbPrevIndex
  353. )
  354. /*++
  355. Routine Description:
  356. Finds the next occurance of lpszHeaderName in the header array, uses
  357. a cached table of well known headers to accerlate the search if the
  358. string is a known header.
  359. N.B. This function MUST be called with the headers already locked
  360. Arguments:
  361. Return Value:
  362. DWORD - index to Slot in array, or INVALID_HEADER_SLOT if not found
  363. --*/
  364. {
  365. //
  366. // Now see if this is a known header passed in as a string,
  367. // If it is, we save ourselves the loop, and just map it right in to a known header
  368. //
  369. DWORD dwKnownQueryIndex = GlobalHeaderHashs[(dwHash % MAX_HEADER_HASH_SIZE)];
  370. *lpdwQueryIndex = INVALID_HEADER_SLOT;
  371. if ( dwKnownQueryIndex != 0 )
  372. {
  373. dwKnownQueryIndex--;
  374. if ( ((int)dwHeaderNameLength >= GlobalKnownHeaders[dwKnownQueryIndex].Length) &&
  375. strnicmp(lpszHeaderName,
  376. GlobalKnownHeaders[dwKnownQueryIndex].Text,
  377. GlobalKnownHeaders[dwKnownQueryIndex].Length) == 0)
  378. {
  379. *lpdwQueryIndex = dwKnownQueryIndex;
  380. INET_ASSERT((int)(dwHeaderNameLength) == GlobalKnownHeaders[dwKnownQueryIndex].Length);
  381. if ( lplpbPrevIndex )
  382. {
  383. return FastNukeFind(
  384. dwKnownQueryIndex,
  385. dwIndex,
  386. lplpbPrevIndex
  387. );
  388. }
  389. else
  390. {
  391. return FastFind(
  392. dwKnownQueryIndex,
  393. dwIndex
  394. );
  395. }
  396. }
  397. }
  398. //
  399. // Otherwise we painfully enumerate the whole array of headers
  400. //
  401. for (DWORD i = 0; i < _TotalSlots; ++i)
  402. {
  403. HEADER_STRING * pString;
  404. pString = &_lpHeaders[i];
  405. if (!pString->HaveString()) {
  406. continue;
  407. }
  408. if (pString->HashStrnicmp(lpBase,
  409. lpszHeaderName,
  410. dwHeaderNameLength,
  411. dwHash) == 0)
  412. {
  413. //
  414. // if we haven't reached the required index yet, continue
  415. //
  416. if (dwIndex != 0) {
  417. --dwIndex;
  418. continue;
  419. }
  420. return i; // found index/slot
  421. }
  422. }
  423. return INVALID_HEADER_SLOT; // not found
  424. }
  425. DWORD
  426. inline
  427. HTTP_HEADERS::FastFind(
  428. IN DWORD dwQueryIndex,
  429. IN DWORD dwIndex
  430. )
  431. /*++
  432. Routine Description:
  433. Finds the next occurance of a known header string in the lpHeaders array.
  434. Since this is a known string, an index is used to refer to it.
  435. A cached table of well known headers is used to accerlate the search.
  436. N.B. This function MUST be called with the headers already locked
  437. Arguments:
  438. Return Value:
  439. DWORD - index to Slot in array, or INVALID_HEADER_SLOT if not found
  440. --*/
  441. {
  442. DWORD dwSlot;
  443. dwSlot = _bKnownHeaders[dwQueryIndex];
  444. while ( (dwIndex > 0) && (dwSlot < INVALID_HEADER_INDEX) )
  445. {
  446. HEADER_STRING * pString;
  447. pString = &_lpHeaders[dwSlot];
  448. dwSlot = pString->GetNextKnownIndex();
  449. dwIndex--;
  450. }
  451. if ( dwSlot >= INVALID_HEADER_INDEX)
  452. {
  453. return INVALID_HEADER_SLOT;
  454. }
  455. return dwSlot; // found it.
  456. }
  457. DWORD
  458. inline
  459. HTTP_HEADERS::FastNukeFind(
  460. IN DWORD dwQueryIndex,
  461. IN DWORD dwIndex,
  462. OUT BYTE **lplpbPrevIndex
  463. )
  464. /*++
  465. Routine Description:
  466. Finds the next occurance of a known header string in the lpHeaders array.
  467. Since this is a known string, an index is used to refer to it.
  468. A cached table of well known headers is used to accerlate the search.
  469. Also provides a ptr to ptr to the slot which directs us to the one found.
  470. This is needed for deletion purposes.
  471. N.B. This function MUST be called with the headers already locked
  472. Arguments:
  473. Return Value:
  474. DWORD - index to Slot in array, or INVALID_HEADER_SLOT if not found
  475. --*/
  476. {
  477. BYTE *lpbSlot;
  478. *lplpbPrevIndex = lpbSlot = &_bKnownHeaders[dwQueryIndex];
  479. dwIndex++;
  480. while ( (dwIndex > 0) && (*lpbSlot < INVALID_HEADER_INDEX) )
  481. {
  482. HEADER_STRING * pString;
  483. pString = &_lpHeaders[*lpbSlot];
  484. *lplpbPrevIndex = lpbSlot;
  485. lpbSlot = pString->GetNextKnownIndexPtr();
  486. dwIndex--;
  487. }
  488. if ( **lplpbPrevIndex >= INVALID_HEADER_INDEX ||
  489. dwIndex > 0 )
  490. {
  491. return INVALID_HEADER_SLOT;
  492. }
  493. return ((DWORD) **lplpbPrevIndex); // found it.
  494. }
  495. VOID
  496. HTTP_HEADERS::RemoveAllByIndex(
  497. IN DWORD dwQueryIndex
  498. )
  499. /*++
  500. Routine Description:
  501. Removes all Known Headers found in the header array.
  502. N.B. This function MUST be called with the headers already locked
  503. Arguments:
  504. dwQueryIndex - index to known header string to remove from array.
  505. Return Value:
  506. None.
  507. --*/
  508. {
  509. BYTE bSlot;
  510. BYTE bPrevSlot;
  511. bSlot = bPrevSlot = _bKnownHeaders[dwQueryIndex];
  512. while (bSlot < INVALID_HEADER_INDEX)
  513. {
  514. HEADER_STRING * pString;
  515. bPrevSlot = bSlot;
  516. pString = &_lpHeaders[bSlot];
  517. bSlot = (BYTE) pString->GetNextKnownIndex();
  518. RemoveHeader(bPrevSlot, dwQueryIndex, &_bKnownHeaders[dwQueryIndex]);
  519. }
  520. _bKnownHeaders[dwQueryIndex] = INVALID_HEADER_INDEX;
  521. return;
  522. }
  523. BOOL
  524. inline
  525. HTTP_HEADERS::HeaderMatch(
  526. IN DWORD dwHash,
  527. IN LPSTR lpszHeaderName,
  528. IN DWORD dwHeaderNameLength,
  529. OUT DWORD *lpdwQueryIndex
  530. )
  531. /*++
  532. Routine Description:
  533. Looks up a Known HTTP header string using its Hash value and
  534. string contained the name of the header.
  535. Arguments:
  536. dwHash - Hash value of header name string
  537. lpszHeaderName - name of header we are matching
  538. dwHeaderNameLength - length of header name string
  539. lpdwQueryIndex - If found, this is the HTTP_QUERY_* based index to the header.
  540. Return Value:
  541. BOOL
  542. Success - The string and hash matched againsted a known header
  543. Failure - There is no known header for that hash & string pair.
  544. --*/
  545. {
  546. *lpdwQueryIndex = GlobalHeaderHashs[(dwHash % MAX_HEADER_HASH_SIZE)];
  547. if ( *lpdwQueryIndex != 0 )
  548. {
  549. (*lpdwQueryIndex)--;
  550. if ( ((int)dwHeaderNameLength == GlobalKnownHeaders[*lpdwQueryIndex].Length) &&
  551. strnicmp(lpszHeaderName,
  552. GlobalKnownHeaders[*lpdwQueryIndex].Text,
  553. GlobalKnownHeaders[*lpdwQueryIndex].Length) == 0)
  554. {
  555. return TRUE;
  556. }
  557. }
  558. return FALSE;
  559. }
  560. BYTE
  561. inline
  562. HTTP_HEADERS::FastAdd(
  563. IN DWORD dwQueryIndex,
  564. IN DWORD dwSlot
  565. )
  566. /*++
  567. Routine Description:
  568. Rapidly adds a known string to the header array, this function
  569. is used to matain coherency of the _bKnownHeaders which
  570. contained indexed offsets into the header array for known headers.
  571. Note that this function is used instead of latter listed below
  572. in order to maintain proper order in headers received.
  573. N.B. This function MUST be called with the headers already locked
  574. Arguments:
  575. dwQueryIndex - index to known header string to remove from array.
  576. dwSlot - Slot in which this header is being added.
  577. Return Value:
  578. None.
  579. --*/
  580. {
  581. BYTE *lpbSlot;
  582. lpbSlot = &_bKnownHeaders[dwQueryIndex];
  583. while ( (*lpbSlot < INVALID_HEADER_INDEX) )
  584. {
  585. HEADER_STRING * pString;
  586. pString = &_lpHeaders[*lpbSlot];
  587. lpbSlot = pString->GetNextKnownIndexPtr();
  588. }
  589. INET_ASSERT(*lpbSlot == INVALID_HEADER_INDEX);
  590. *lpbSlot = (BYTE) dwSlot;
  591. return INVALID_HEADER_INDEX;
  592. }
  593. //BYTE
  594. //inline
  595. //HTTP_HEADERS::FastAdd(
  596. // IN DWORD dwQueryIndex,
  597. // IN DWORD dwSlot
  598. // )
  599. //{
  600. // BYTE bOldSlot;
  601. //
  602. // bOldSlot = _bKnownHeaders[dwQueryIndex];
  603. // _bKnownHeaders[dwQueryIndex] = (BYTE) dwSlot;
  604. //
  605. // return bOldSlot;
  606. //}
  607. DWORD
  608. HTTP_HEADERS::AddHeader(
  609. IN LPSTR lpszHeaderName,
  610. IN DWORD dwHeaderNameLength,
  611. IN LPSTR lpszHeaderValue,
  612. IN DWORD dwHeaderValueLength,
  613. IN DWORD dwIndex,
  614. IN DWORD dwFlags
  615. )
  616. /*++
  617. Routine Description:
  618. Adds a single header to the array of headers, given the header name and
  619. value. Called via HttpOpenRequest()
  620. Arguments:
  621. lpszHeaderName - pointer to name of header to add, e.g. "Accept:"
  622. dwHeaderNameLength - length of the header name
  623. lpszHeaderValue - pointer to value of header to add, e.g. "text/html"
  624. dwHeaderValueLength - length of the header value
  625. dwIndex - if coalescing headers, index of header to update
  626. dwFlags - flags controlling function:
  627. COALESCE_HEADER_WITH_COMMA
  628. COALESCE_HEADER_WITH_SEMICOLON
  629. - headers of the same name can be combined
  630. CLEAN_HEADER
  631. - header is supplied by user, so we must ensure
  632. it has correct format
  633. Return Value:
  634. DWORD
  635. Success - ERROR_SUCCESS
  636. Failure - ERROR_NOT_ENOUGH_MEMORY
  637. Ran out of memory allocating string
  638. ERROR_INVALID_PARAMETER
  639. The header value was bad
  640. --*/
  641. {
  642. DEBUG_ENTER((DBG_HTTP,
  643. Dword,
  644. "AddHeader",
  645. "%.*q, %d, %.*q, %d, %d, %#x",
  646. min(dwHeaderNameLength + 1, 80),
  647. lpszHeaderName,
  648. dwHeaderNameLength,
  649. min(dwHeaderValueLength + 1, 80),
  650. lpszHeaderValue,
  651. dwHeaderValueLength,
  652. dwIndex,
  653. dwFlags
  654. ));
  655. PERF_ENTER(AddHeader);
  656. DWORD error = ERROR_HTTP_HEADER_NOT_FOUND;
  657. if (!LockHeaders())
  658. {
  659. error = ERROR_NOT_ENOUGH_MEMORY;
  660. goto quit;
  661. }
  662. INET_ASSERT(lpszHeaderName != NULL);
  663. INET_ASSERT(*lpszHeaderName != '\0');
  664. INET_ASSERT(dwHeaderNameLength != 0);
  665. INET_ASSERT(lpszHeaderValue != NULL);
  666. //INET_ASSERT(*lpszHeaderValue != '\0'); A header with no value is allowed
  667. //INET_ASSERT(dwHeaderValueLength != 0); A header with no value is allowed
  668. INET_ASSERT(_FreeSlots <= _TotalSlots);
  669. //
  670. // we may have been handed a header with a trailing colon. We don't care
  671. // for such nasty imagery
  672. //
  673. if (lpszHeaderName[dwHeaderNameLength - 1] == ':') {
  674. --dwHeaderNameLength;
  675. }
  676. DWORD dwQueryIndex;
  677. DWORD dwHash = CalculateHashNoCase(lpszHeaderName, dwHeaderNameLength);
  678. //
  679. // if we are coalescing headers then find a header with the same name
  680. //
  681. if ((dwFlags & COALESCE_HEADER_WITH_COMMA) ||
  682. (dwFlags & COALESCE_HEADER_WITH_SEMICOLON) )
  683. {
  684. DWORD dwSlot;
  685. dwSlot = SlowFind(
  686. NULL,
  687. lpszHeaderName,
  688. dwHeaderNameLength,
  689. dwIndex,
  690. dwHash,
  691. &dwQueryIndex,
  692. NULL
  693. );
  694. if (dwSlot != ((DWORD) -1))
  695. {
  696. if (dwHeaderValueLength > 0) // don't bother appending if empty value
  697. {
  698. HEADER_STRING * pString;
  699. pString = &_lpHeaders[dwSlot];
  700. //
  701. // found what we are looking for. Coalesce it
  702. //
  703. pString->ResizeString((sizeof("; ")-1) + dwHeaderValueLength); // save us from multiple reallocs
  704. pString->Strncat(
  705. (dwFlags & COALESCE_HEADER_WITH_SEMICOLON) ?
  706. "; " :
  707. ", ",
  708. 2);
  709. pString->Strncat(lpszHeaderValue, dwHeaderValueLength);
  710. _HeadersLength += 2 + dwHeaderValueLength;
  711. }
  712. error = ERROR_SUCCESS;
  713. }
  714. }
  715. else
  716. {
  717. //
  718. // Check to verify that the header we're adding is a known header,
  719. // If its a known header we use dwQueryIndex to update the known header array
  720. // otherwise, IF ITS NOT, we make sure to set dwQueryIndex to INVALID_...
  721. //
  722. if (! HeaderMatch(dwHash, lpszHeaderName, dwHeaderNameLength, &dwQueryIndex) )
  723. {
  724. dwQueryIndex = INVALID_HEADER_SLOT;
  725. }
  726. /*
  727. // Perhaps this more efficent ???
  728. dwQueryIndex = GlobalHeaderHashs[(dwHash % MAX_HEADER_HASH_SIZE)];
  729. if ( dwQueryIndex != 0 )
  730. {
  731. dwQueryIndex--;
  732. if ( ((int)dwHeaderNameLength < GlobalKnownHeaders[dwQueryIndex].Length) ||
  733. strnicmp(lpszHeaderName,
  734. GlobalKnownHeaders[dwQueryIndex].Text,
  735. GlobalKnownHeaders[dwQueryIndex].Length) != 0)
  736. {
  737. dwQueryIndex = INVALID_HEADER_SLOT;
  738. }
  739. }
  740. else
  741. {
  742. dwQueryIndex = INVALID_HEADER_SLOT;
  743. }
  744. */
  745. }
  746. //
  747. // if we didn't find the header value or we are not coalescing then add the
  748. // header
  749. //
  750. if (error == ERROR_HTTP_HEADER_NOT_FOUND)
  751. {
  752. //
  753. // find the next slot for this header
  754. //
  755. HEADER_STRING * freeHeader;
  756. DWORD iSlot;
  757. freeHeader = FindFreeSlot(&iSlot);
  758. if (freeHeader == NULL) {
  759. error = GetError();
  760. INET_ASSERT(error != ERROR_SUCCESS);
  761. goto Cleanup;
  762. }
  763. freeHeader->CreateStringBuffer((LPVOID)lpszHeaderName,
  764. dwHeaderNameLength,
  765. dwHeaderNameLength
  766. + sizeof(": ") - 1
  767. + dwHeaderValueLength
  768. + 1 // for extra NULL terminator
  769. );
  770. if (freeHeader->IsError()) {
  771. error = ::GetLastError();
  772. INET_ASSERT(error != ERROR_SUCCESS);
  773. goto Cleanup;
  774. }
  775. freeHeader->Strncat((LPVOID)": ", sizeof(": ") - 1);
  776. if (dwHeaderValueLength > 0)
  777. {
  778. freeHeader->Strncat((LPVOID)lpszHeaderValue, dwHeaderValueLength);
  779. }
  780. _HeadersLength += dwHeaderNameLength
  781. + (sizeof(": ") - 1)
  782. + dwHeaderValueLength
  783. + (sizeof("\r\n") - 1)
  784. ;
  785. freeHeader->SetHash(dwHash);
  786. if ( dwQueryIndex != INVALID_HEADER_SLOT )
  787. {
  788. freeHeader->SetNextKnownIndex(FastAdd(dwQueryIndex, iSlot));
  789. }
  790. error = ERROR_SUCCESS;
  791. }
  792. Cleanup:
  793. UnlockHeaders();
  794. quit:
  795. PERF_LEAVE(AddHeader);
  796. DEBUG_LEAVE(error);
  797. return error;
  798. }
  799. DWORD
  800. HTTP_HEADERS::AddHeader(
  801. IN DWORD dwQueryIndex,
  802. IN LPSTR lpszHeaderValue,
  803. IN DWORD dwHeaderValueLength,
  804. IN DWORD dwIndex,
  805. IN DWORD dwFlags
  806. )
  807. /*++
  808. Routine Description:
  809. Adds a single header to the array of headers, given the header name and
  810. value. Called via HttpOpenRequest()
  811. Arguments:
  812. dwQueryIndex - a index into a array of known HTTP headers, see wininet.h HTTP_QUERY_* codes
  813. lpszHeaderValue - pointer to value of header to add, e.g. "text/html"
  814. dwHeaderValueLength - length of the header value
  815. dwIndex - if coalescing headers, index of header to update
  816. dwFlags - flags controlling function:
  817. COALESCE_HEADER_WITH_COMMA
  818. COALESCE_HEADER_WITH_SEMICOLON
  819. - headers of the same name can be combined
  820. CLEAN_HEADER
  821. - header is supplied by user, so we must ensure
  822. it has correct format
  823. Return Value:
  824. DWORD
  825. Success - ERROR_SUCCESS
  826. Failure - ERROR_NOT_ENOUGH_MEMORY
  827. Ran out of memory allocating string
  828. ERROR_INVALID_PARAMETER
  829. The header value was bad
  830. --*/
  831. {
  832. DEBUG_ENTER((DBG_HTTP,
  833. Dword,
  834. "AddHeader",
  835. "%q, %u, %.*q, %d, %d, %#x",
  836. GlobalKnownHeaders[dwQueryIndex].Text,
  837. dwQueryIndex,
  838. min(dwHeaderValueLength + 1, 80),
  839. lpszHeaderValue,
  840. dwHeaderValueLength,
  841. dwIndex,
  842. dwFlags
  843. ));
  844. PERF_ENTER(AddHeader);
  845. INET_ASSERT(dwQueryIndex <= HTTP_QUERY_MAX);
  846. INET_ASSERT(lpszHeaderValue != NULL);
  847. // INET_ASSERT(*lpszHeaderValue != '\0'); A header with no value is allowed
  848. // INET_ASSERT(dwHeaderValueLength != 0); A header with no value is allowed
  849. INET_ASSERT(_FreeSlots <= _TotalSlots);
  850. DWORD error = ERROR_HTTP_HEADER_NOT_FOUND;
  851. LPSTR lpszHeaderName;
  852. DWORD dwHeaderNameLength;
  853. DWORD dwHash;
  854. dwHash = GlobalKnownHeaders[dwQueryIndex].HashVal;
  855. lpszHeaderName = GlobalKnownHeaders[dwQueryIndex].Text;
  856. dwHeaderNameLength = GlobalKnownHeaders[dwQueryIndex].Length;
  857. //
  858. // if we are coalescing headers then find a header with the same name
  859. //
  860. if ((dwFlags & COALESCE_HEADER_WITH_COMMA) ||
  861. (dwFlags & COALESCE_HEADER_WITH_SEMICOLON) )
  862. {
  863. DWORD dwSlot;
  864. dwSlot = FastFind(
  865. dwQueryIndex,
  866. dwIndex
  867. );
  868. if (dwSlot != INVALID_HEADER_SLOT)
  869. {
  870. if (dwHeaderValueLength > 0) // don't bother appending if empty value
  871. {
  872. HEADER_STRING * pString;
  873. pString = &_lpHeaders[dwSlot];
  874. //
  875. // found what we are looking for. Coalesce it
  876. //
  877. pString->ResizeString((sizeof("; ")-1) + dwHeaderValueLength); // save us from multiple reallocs
  878. pString->Strncat(
  879. (dwFlags & COALESCE_HEADER_WITH_SEMICOLON) ?
  880. "; " :
  881. ", ",
  882. 2);
  883. pString->Strncat(lpszHeaderValue, dwHeaderValueLength);
  884. _HeadersLength += 2 + dwHeaderValueLength;
  885. }
  886. error = ERROR_SUCCESS;
  887. }
  888. }
  889. //
  890. // if we didn't find the header value or we are not coalescing then add the
  891. // header
  892. //
  893. if (error == ERROR_HTTP_HEADER_NOT_FOUND)
  894. {
  895. //
  896. // find the next slot for this header
  897. //
  898. HEADER_STRING * freeHeader;
  899. DWORD iSlot;
  900. freeHeader = FindFreeSlot(&iSlot);
  901. if (freeHeader == NULL) {
  902. error = GetError();
  903. INET_ASSERT(error != ERROR_SUCCESS);
  904. goto quit;
  905. }
  906. freeHeader->CreateStringBuffer((LPVOID)lpszHeaderName,
  907. dwHeaderNameLength,
  908. dwHeaderNameLength
  909. + sizeof(": ") - 1
  910. + dwHeaderValueLength
  911. + 1 // for extra NULL terminator
  912. );
  913. if (freeHeader->IsError()) {
  914. error = ::GetLastError();
  915. INET_ASSERT(error != ERROR_SUCCESS);
  916. goto quit;
  917. }
  918. freeHeader->Strncat((LPVOID)": ", sizeof(": ") - 1);
  919. if (dwHeaderValueLength > 0)
  920. {
  921. freeHeader->Strncat((LPVOID)lpszHeaderValue, dwHeaderValueLength);
  922. }
  923. _HeadersLength += dwHeaderNameLength
  924. + (sizeof(": ") - 1)
  925. + dwHeaderValueLength
  926. + (sizeof("\r\n") - 1)
  927. ;
  928. freeHeader->SetHash(dwHash);
  929. freeHeader->SetNextKnownIndex(FastAdd(dwQueryIndex, iSlot));
  930. error = ERROR_SUCCESS;
  931. }
  932. quit:
  933. PERF_LEAVE(AddHeader);
  934. DEBUG_LEAVE(error);
  935. return error;
  936. }
  937. DWORD
  938. HTTP_HEADERS::ReplaceHeader(
  939. IN LPSTR lpszHeaderName,
  940. IN DWORD dwHeaderNameLength,
  941. IN LPSTR lpszHeaderValue,
  942. IN DWORD dwHeaderValueLength,
  943. IN DWORD dwIndex,
  944. IN DWORD dwFlags
  945. )
  946. /*++
  947. Routine Description:
  948. Replaces a HTTP (request) header. The header can be replaced with a NULL
  949. value, meaning that the header is removed
  950. Arguments:
  951. lpszHeaderName - pointer to the header name
  952. dwHeaderNameLength - length of the header name
  953. lpszHeaderValue - pointer to the header value
  954. dwHeaderValueLength - length of the header value
  955. dwIndex - index of header to replace
  956. dwFlags - flags controlling function. Allowed flags are:
  957. COALESCE_HEADER_WITH_COMMA
  958. COALESCE_HEADER_WITH_SEMICOLON
  959. - headers of the same name can be combined
  960. ADD_HEADER
  961. - if the header-name is not found and there is
  962. a valid header-value, then the header is added
  963. ADD_HEADER_IF_NEW
  964. - if the header-name exists then we return an
  965. error, else we add the header-value
  966. Return Value:
  967. DWORD
  968. Success - ERROR_SUCCESS
  969. Failure - ERROR_HTTP_HEADER_NOT_FOUND
  970. The requested header wasn't found
  971. ERROR_HTTP_HEADER_ALREADY_EXISTS
  972. The header already exists, and was not added or replaced
  973. ERROR_NOT_ENOUGH_MEMORY
  974. Ran out of memory trying to acquire lock
  975. --*/
  976. {
  977. DEBUG_ENTER((DBG_HTTP,
  978. Dword,
  979. "ReplaceHeader",
  980. "%.*q, %d, %.*q, %d, %d, %#x",
  981. min(dwHeaderNameLength + 1, 80),
  982. lpszHeaderName,
  983. dwHeaderNameLength,
  984. min(dwHeaderValueLength + 1, 80),
  985. lpszHeaderValue,
  986. dwHeaderValueLength,
  987. dwIndex,
  988. dwFlags
  989. ));
  990. PERF_ENTER(ReplaceHeader);
  991. INET_ASSERT(lpszHeaderName != NULL);
  992. INET_ASSERT(dwHeaderNameLength != 0);
  993. INET_ASSERT(lpszHeaderName[dwHeaderNameLength - 1] != ':');
  994. DWORD error = ERROR_HTTP_HEADER_NOT_FOUND;
  995. DWORD dwHash = CalculateHashNoCase(lpszHeaderName, dwHeaderNameLength);
  996. DWORD dwSlot;
  997. DWORD dwQueryIndex;
  998. BYTE *pbPrevByte;
  999. if (!LockHeaders())
  1000. {
  1001. error = ERROR_NOT_ENOUGH_MEMORY;
  1002. goto quit;
  1003. }
  1004. dwSlot = SlowFind(
  1005. NULL,
  1006. lpszHeaderName,
  1007. dwHeaderNameLength,
  1008. dwIndex,
  1009. dwHash,
  1010. &dwQueryIndex,
  1011. &pbPrevByte
  1012. );
  1013. if ( dwSlot != ((DWORD) -1))
  1014. {
  1015. //
  1016. // if ADD_HEADER_IF_NEW is set, then we already have the header
  1017. //
  1018. if (dwFlags & ADD_HEADER_IF_NEW) {
  1019. error = ERROR_HTTP_HEADER_ALREADY_EXISTS;
  1020. goto Cleanup;
  1021. }
  1022. //
  1023. // for both replace and remove operations, we are going to remove
  1024. // the current header
  1025. //
  1026. RemoveHeader(dwSlot, dwQueryIndex, pbPrevByte);
  1027. //
  1028. // if replacing then add the new header value
  1029. //
  1030. if (dwHeaderValueLength != 0)
  1031. {
  1032. if ( dwQueryIndex != ((DWORD) -1) )
  1033. {
  1034. error = AddHeader(dwQueryIndex,
  1035. lpszHeaderValue,
  1036. dwHeaderValueLength,
  1037. 0,
  1038. dwFlags
  1039. );
  1040. }
  1041. else
  1042. {
  1043. error = AddHeader(lpszHeaderName,
  1044. dwHeaderNameLength,
  1045. lpszHeaderValue,
  1046. dwHeaderValueLength,
  1047. 0,
  1048. dwFlags
  1049. );
  1050. }
  1051. } else {
  1052. error = ERROR_SUCCESS;
  1053. }
  1054. }
  1055. //
  1056. // if we didn't find the header but ADD_HEADER is set then we simply add it
  1057. // but only if the value length is not zero
  1058. //
  1059. if ((error == ERROR_HTTP_HEADER_NOT_FOUND)
  1060. && (dwHeaderValueLength != 0)
  1061. && (dwFlags & (ADD_HEADER | ADD_HEADER_IF_NEW)))
  1062. {
  1063. if ( dwQueryIndex != ((DWORD) -1) )
  1064. {
  1065. error = AddHeader(dwQueryIndex,
  1066. lpszHeaderValue,
  1067. dwHeaderValueLength,
  1068. 0,
  1069. dwFlags
  1070. );
  1071. }
  1072. else
  1073. {
  1074. error = AddHeader(lpszHeaderName,
  1075. dwHeaderNameLength,
  1076. lpszHeaderValue,
  1077. dwHeaderValueLength,
  1078. 0,
  1079. dwFlags
  1080. );
  1081. }
  1082. }
  1083. Cleanup:
  1084. UnlockHeaders();
  1085. quit:
  1086. PERF_LEAVE(ReplaceHeader);
  1087. DEBUG_LEAVE(error);
  1088. return error;
  1089. }
  1090. DWORD
  1091. HTTP_HEADERS::ReplaceHeader(
  1092. IN DWORD dwQueryIndex,
  1093. IN LPSTR lpszHeaderValue,
  1094. IN DWORD dwHeaderValueLength,
  1095. IN DWORD dwIndex,
  1096. IN DWORD dwFlags
  1097. )
  1098. /*++
  1099. Routine Description:
  1100. Replaces a HTTP (request) header. The header can be replaced with a NULL
  1101. value, meaning that the header is removed
  1102. Arguments:
  1103. lpszHeaderValue - pointer to the header value
  1104. dwQueryIndex - a index into a array of known HTTP headers, see wininet.h HTTP_QUERY_* codes
  1105. dwHeaderValueLength - length of the header value
  1106. dwIndex - index of header to replace
  1107. dwFlags - flags controlling function. Allowed flags are:
  1108. COALESCE_HEADER_WITH_COMMA
  1109. COALESCE_HEADER_WITH_SEMICOLON
  1110. - headers of the same name can be combined
  1111. ADD_HEADER
  1112. - if the header-name is not found and there is
  1113. a valid header-value, then the header is added
  1114. ADD_HEADER_IF_NEW
  1115. - if the header-name exists then we return an
  1116. error, else we add the header-value
  1117. Return Value:
  1118. DWORD
  1119. Success - ERROR_SUCCESS
  1120. Failure - ERROR_HTTP_HEADER_NOT_FOUND
  1121. The requested header wasn't found
  1122. ERROR_HTTP_HEADER_ALREADY_EXISTS
  1123. The header already exists, and was not added or replaced
  1124. ERROR_NOT_ENOUGH_MEMORY
  1125. Ran out of memory trying to acquire lock
  1126. --*/
  1127. {
  1128. DEBUG_ENTER((DBG_HTTP,
  1129. Dword,
  1130. "ReplaceHeader",
  1131. "%q, %u, %.*q, %d, %d, %#x",
  1132. GlobalKnownHeaders[dwQueryIndex].Text,
  1133. dwQueryIndex,
  1134. min(dwHeaderValueLength + 1, 80),
  1135. lpszHeaderValue,
  1136. dwHeaderValueLength,
  1137. dwIndex,
  1138. dwFlags
  1139. ));
  1140. PERF_ENTER(ReplaceHeader);
  1141. DWORD error = ERROR_HTTP_HEADER_NOT_FOUND;
  1142. DWORD dwSlot;
  1143. BYTE *pbPrevByte;
  1144. if (!LockHeaders())
  1145. {
  1146. error = ERROR_NOT_ENOUGH_MEMORY;
  1147. goto quit;
  1148. }
  1149. dwSlot = FastNukeFind(
  1150. dwQueryIndex,
  1151. dwIndex,
  1152. &pbPrevByte
  1153. );
  1154. if ( dwSlot != INVALID_HEADER_SLOT)
  1155. {
  1156. //
  1157. // if ADD_HEADER_IF_NEW is set, then we already have the header
  1158. //
  1159. if (dwFlags & ADD_HEADER_IF_NEW) {
  1160. error = ERROR_HTTP_HEADER_ALREADY_EXISTS;
  1161. goto Cleanup;
  1162. }
  1163. //
  1164. // for both replace and remove operations, we are going to remove
  1165. // the current header
  1166. //
  1167. RemoveHeader(dwSlot, dwQueryIndex, pbPrevByte);
  1168. //
  1169. // if replacing then add the new header value
  1170. //
  1171. if (dwHeaderValueLength != 0)
  1172. {
  1173. error = AddHeader(dwQueryIndex,
  1174. lpszHeaderValue,
  1175. dwHeaderValueLength,
  1176. 0,
  1177. dwFlags
  1178. );
  1179. } else {
  1180. error = ERROR_SUCCESS;
  1181. }
  1182. }
  1183. //
  1184. // if we didn't find the header but ADD_HEADER is set then we simply add it
  1185. // but only if the value length is not zero
  1186. //
  1187. if ((error == ERROR_HTTP_HEADER_NOT_FOUND)
  1188. && (dwHeaderValueLength != 0)
  1189. && (dwFlags & (ADD_HEADER | ADD_HEADER_IF_NEW)))
  1190. {
  1191. error = AddHeader(dwQueryIndex,
  1192. lpszHeaderValue,
  1193. dwHeaderValueLength,
  1194. 0,
  1195. dwFlags
  1196. );
  1197. }
  1198. Cleanup:
  1199. UnlockHeaders();
  1200. quit:
  1201. PERF_LEAVE(ReplaceHeader);
  1202. DEBUG_LEAVE(error);
  1203. return error;
  1204. }
  1205. DWORD
  1206. HTTP_HEADERS::FindHeader(
  1207. IN LPSTR lpBase,
  1208. IN LPCSTR lpszHeaderName,
  1209. IN DWORD dwHeaderNameLength,
  1210. IN DWORD dwModifiers,
  1211. OUT LPVOID lpBuffer,
  1212. IN OUT LPDWORD lpdwBufferLength,
  1213. IN OUT LPDWORD lpdwIndex
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. Finds a request or response header
  1218. Arguments:
  1219. lpBase - base for offset HEADER_STRINGs
  1220. lpszHeaderName - pointer to header name
  1221. dwHeaderNameLength - length of header name
  1222. dwModifiers - flags which modify returned value
  1223. lpBuffer - pointer to buffer for results
  1224. lpdwBufferLength - IN: length of lpBuffer
  1225. OUT: length of results, or required length of lpBuffer
  1226. lpdwIndex - IN: 0-based index of header to find
  1227. OUT: next header index if success returned
  1228. Return Value:
  1229. DWORD
  1230. Success - ERROR_SUCCESS
  1231. Failure - ERROR_INSUFFICIENT_BUFFER
  1232. *lpdwBufferLength contains the amount required
  1233. ERROR_HTTP_HEADER_NOT_FOUND
  1234. The specified header (or index of header) was not found
  1235. ERROR_NOT_ENOUGH_MEMORY
  1236. Ran out of memory trying to acquire lock
  1237. --*/
  1238. {
  1239. DEBUG_ENTER((DBG_HTTP,
  1240. Dword,
  1241. "HTTP_HEADERS::FindHeader",
  1242. "%#x [%.*q], %d, %#x, %#x [%#x], %#x, %#x [%d]",
  1243. lpszHeaderName,
  1244. min(dwHeaderNameLength + 1, 80),
  1245. lpszHeaderName,
  1246. dwHeaderNameLength,
  1247. lpBuffer,
  1248. lpdwBufferLength,
  1249. *lpdwBufferLength,
  1250. dwModifiers,
  1251. lpdwIndex,
  1252. *lpdwIndex
  1253. ));
  1254. PERF_ENTER(FindHeader);
  1255. INET_ASSERT(lpdwIndex != NULL);
  1256. DWORD error = ERROR_HTTP_HEADER_NOT_FOUND;
  1257. DWORD dwSlot;
  1258. HEADER_STRING * pString;
  1259. DWORD dwQueryIndex;
  1260. DWORD dwHash = CalculateHashNoCase(lpszHeaderName, dwHeaderNameLength);
  1261. if (!LockHeaders())
  1262. {
  1263. error = ERROR_NOT_ENOUGH_MEMORY;
  1264. goto quit;
  1265. }
  1266. dwSlot = SlowFind(
  1267. lpBase,
  1268. lpszHeaderName,
  1269. dwHeaderNameLength,
  1270. *lpdwIndex,
  1271. dwHash,
  1272. &dwQueryIndex,
  1273. NULL
  1274. );
  1275. if ( dwSlot != ((DWORD) -1) )
  1276. {
  1277. pString = &_lpHeaders[dwSlot];
  1278. //
  1279. // found the header - get to the value
  1280. //
  1281. DWORD stringLen;
  1282. LPSTR value;
  1283. stringLen = pString->StringLength();
  1284. INET_ASSERT(stringLen > dwHeaderNameLength);
  1285. //
  1286. // get a pointer to the value string
  1287. //
  1288. value = pString->StringAddress(lpBase) + dwHeaderNameLength;
  1289. stringLen -= dwHeaderNameLength;
  1290. //
  1291. // the input string could be a substring of a different header
  1292. //
  1293. //INET_ASSERT(*value != ':');
  1294. //
  1295. // find the first non-space character in the value.
  1296. //
  1297. // N.B.: Servers can return empty headers, so we may end up with a
  1298. // zero length string
  1299. //
  1300. do {
  1301. ++value;
  1302. --stringLen;
  1303. } while ((stringLen > 0) && (*value == ' '));
  1304. //
  1305. // get the data in the format requested by the app
  1306. //
  1307. LPVOID lpData = NULL;
  1308. DWORD dwDataSize = 0;
  1309. DWORD dwRequiredSize = 0;
  1310. SYSTEMTIME systemTime;
  1311. DWORD number;
  1312. //
  1313. // error is no longer ERROR_HTTP_HEADER_NOT_FOUND, but it might not
  1314. // really be success either...
  1315. //
  1316. error = ERROR_SUCCESS;
  1317. if (dwModifiers & HTTP_QUERY_FLAG_SYSTEMTIME) {
  1318. char buf[DATE_AND_TIME_STRING_BUFFER_LENGTH];
  1319. if (stringLen < sizeof(buf)) {
  1320. //
  1321. // value probably does not point at a zero-terminated string
  1322. // which HttpDateToSystemTime() expects, so we make a copy
  1323. // and terminate it
  1324. //
  1325. memcpy((LPVOID)buf, (LPVOID)value, stringLen);
  1326. buf[stringLen] = '\0';
  1327. if (HttpDateToSystemTime(buf, &systemTime)) {
  1328. lpData = (LPVOID)&systemTime;
  1329. dwRequiredSize = dwDataSize = sizeof(systemTime);
  1330. } else {
  1331. //
  1332. // couldn't convert date/time. Presume header must be bogus
  1333. //
  1334. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  1335. DEBUG_PRINT(HTTP,
  1336. ERROR,
  1337. ("cannot convert %.40q to SYSTEMTIME\n",
  1338. value
  1339. ));
  1340. }
  1341. } else {
  1342. //
  1343. // we would break the date/time buffer!
  1344. //
  1345. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1346. }
  1347. } else if (dwModifiers & HTTP_QUERY_FLAG_NUMBER) {
  1348. if (isdigit(*value)) {
  1349. number = 0;
  1350. for (int i = 0;
  1351. (stringLen > 0) && isdigit(value[i]);
  1352. ++i, --stringLen) {
  1353. number = number * 10 + (DWORD)(value[i] - '0');
  1354. }
  1355. lpData = (LPVOID)&number;
  1356. dwRequiredSize = dwDataSize = sizeof(number);
  1357. } else {
  1358. //
  1359. // not a numeric field. Request must be bogus for this header
  1360. //
  1361. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  1362. DEBUG_PRINT(HTTP,
  1363. ERROR,
  1364. ("cannot convert %.20q to NUMBER\n",
  1365. value
  1366. ));
  1367. }
  1368. } else {
  1369. lpData = (LPVOID)value;
  1370. dwDataSize = stringLen;
  1371. dwRequiredSize = dwDataSize + 1;
  1372. }
  1373. //
  1374. // if error == ERROR_SUCCESS then we can attempt to copy the data
  1375. //
  1376. if (error == ERROR_SUCCESS) {
  1377. if (*lpdwBufferLength < dwRequiredSize) {
  1378. *lpdwBufferLength = dwRequiredSize;
  1379. error = ERROR_INSUFFICIENT_BUFFER;
  1380. } else {
  1381. memcpy(lpBuffer, lpData, dwDataSize);
  1382. *lpdwBufferLength = dwDataSize;
  1383. //
  1384. // if dwRequiredSize > dwDataSize, then this is a variable-
  1385. // length item (i.e. a STRING!) so we add a terminating '\0'
  1386. //
  1387. if (dwRequiredSize > dwDataSize) {
  1388. INET_ASSERT(dwRequiredSize - dwDataSize == 1);
  1389. ((LPSTR)lpBuffer)[dwDataSize] = '\0';
  1390. }
  1391. //
  1392. // successfully retrieved the requested header - bump the
  1393. // index
  1394. //
  1395. ++*lpdwIndex;
  1396. }
  1397. }
  1398. }
  1399. UnlockHeaders();
  1400. quit:
  1401. PERF_LEAVE(FindHeader);
  1402. DEBUG_LEAVE(error);
  1403. return error;
  1404. }
  1405. DWORD
  1406. HTTP_HEADERS::FindHeader(
  1407. IN LPSTR lpBase,
  1408. IN DWORD dwQueryIndex,
  1409. IN DWORD dwModifiers,
  1410. OUT LPVOID lpBuffer,
  1411. IN OUT LPDWORD lpdwBufferLength,
  1412. IN OUT LPDWORD lpdwIndex
  1413. )
  1414. /*++
  1415. Routine Description:
  1416. Finds a request or response header, based on index to the header name we are searching for.
  1417. Arguments:
  1418. lpBase - base for offset HEADER_STRINGs
  1419. dwQueryIndex - a index into a array of known HTTP headers, see wininet.h HTTP_QUERY_* codes
  1420. dwModifiers - flags which modify returned value
  1421. lpBuffer - pointer to buffer for results
  1422. lpdwBufferLength - IN: length of lpBuffer
  1423. OUT: length of results, or required length of lpBuffer
  1424. lpdwIndex - IN: 0-based index of header to find
  1425. OUT: next header index if success returned
  1426. Return Value:
  1427. DWORD
  1428. Success - ERROR_SUCCESS
  1429. Failure - ERROR_INSUFFICIENT_BUFFER
  1430. *lpdwBufferLength contains the amount required
  1431. ERROR_HTTP_HEADER_NOT_FOUND
  1432. The specified header (or index of header) was not found
  1433. --*/
  1434. {
  1435. DWORD error;
  1436. LPSTR lpData;
  1437. DWORD dwDataSize = 0;
  1438. DWORD dwRequiredSize = 0;
  1439. SYSTEMTIME systemTime;
  1440. DWORD number;
  1441. error = FastFindHeader(
  1442. lpBase,
  1443. dwQueryIndex,
  1444. (LPVOID *)&lpData,
  1445. &dwDataSize,
  1446. *lpdwIndex
  1447. );
  1448. if ( error != ERROR_SUCCESS )
  1449. {
  1450. goto quit;
  1451. }
  1452. //
  1453. // get the data in the format requested by the app
  1454. //
  1455. if (dwModifiers & HTTP_QUERY_FLAG_SYSTEMTIME)
  1456. {
  1457. char buf[DATE_AND_TIME_STRING_BUFFER_LENGTH];
  1458. if (dwDataSize < sizeof(buf))
  1459. {
  1460. //
  1461. // value probably does not point at a zero-terminated string
  1462. // which HttpDateToSystemTime() expects, so we make a copy
  1463. // and terminate it
  1464. //
  1465. memcpy((LPVOID)buf, (LPVOID)lpData, dwDataSize);
  1466. buf[dwDataSize] = '\0';
  1467. if (HttpDateToSystemTime(buf, &systemTime)) {
  1468. lpData = (LPSTR)&systemTime;
  1469. dwRequiredSize = dwDataSize = sizeof(systemTime);
  1470. } else {
  1471. //
  1472. // couldn't convert date/time. Presume header must be bogus
  1473. //
  1474. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  1475. DEBUG_PRINT(HTTP,
  1476. ERROR,
  1477. ("cannot convert %.40q to SYSTEMTIME\n",
  1478. lpData
  1479. ));
  1480. }
  1481. }
  1482. else
  1483. {
  1484. //
  1485. // we would break the date/time buffer!
  1486. //
  1487. error = ERROR_WINHTTP_INTERNAL_ERROR;
  1488. }
  1489. }
  1490. else if (dwModifiers & HTTP_QUERY_FLAG_NUMBER)
  1491. {
  1492. if (isdigit(*lpData)) {
  1493. number = 0;
  1494. for (int i = 0;
  1495. (dwDataSize > 0) && isdigit(lpData[i]);
  1496. ++i, --dwDataSize) {
  1497. number = number * 10 + (DWORD)(lpData[i] - '0');
  1498. }
  1499. lpData = (LPSTR)&number;
  1500. dwRequiredSize = dwDataSize = sizeof(number);
  1501. } else {
  1502. //
  1503. // not a numeric field. Request must be bogus for this header
  1504. //
  1505. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  1506. DEBUG_PRINT(HTTP,
  1507. ERROR,
  1508. ("cannot convert %.20q to NUMBER\n",
  1509. lpData
  1510. ));
  1511. }
  1512. }
  1513. else
  1514. {
  1515. dwRequiredSize = dwDataSize + 1;
  1516. }
  1517. //
  1518. // if error == ERROR_SUCCESS then we can attempt to copy the data
  1519. //
  1520. if (error == ERROR_SUCCESS)
  1521. {
  1522. if (*lpdwBufferLength < dwRequiredSize)
  1523. {
  1524. *lpdwBufferLength = dwRequiredSize;
  1525. error = ERROR_INSUFFICIENT_BUFFER;
  1526. }
  1527. else
  1528. {
  1529. memcpy(lpBuffer, lpData, dwDataSize);
  1530. *lpdwBufferLength = dwDataSize;
  1531. //
  1532. // if dwRequiredSize > dwDataSize, then this is a variable-
  1533. // length item (i.e. a STRING!) so we add a terminating '\0'
  1534. //
  1535. if (dwRequiredSize > dwDataSize)
  1536. {
  1537. INET_ASSERT(dwRequiredSize - dwDataSize == 1);
  1538. ((LPSTR)lpBuffer)[dwDataSize] = '\0';
  1539. }
  1540. //
  1541. // successfully retrieved the requested header - bump the
  1542. // index
  1543. //
  1544. ++*lpdwIndex;
  1545. }
  1546. }
  1547. quit:
  1548. return error;
  1549. }
  1550. DWORD
  1551. HTTP_HEADERS::FastFindHeader(
  1552. IN LPSTR lpBase,
  1553. IN DWORD dwQueryIndex,
  1554. OUT LPVOID *lplpBuffer,
  1555. IN OUT LPDWORD lpdwBufferLength,
  1556. IN DWORD dwIndex
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. Finds a request or response header slightly quicker than its higher level
  1561. cousin, FindHeader. Unlike FindHeader this function simply returns
  1562. a pointer and length, and does not copy header data.
  1563. lpBase - base address of strings
  1564. dwQueryIndex - a index into a array known HTTP headers, see wininet.h HTTP_QUERY_* codes
  1565. lplpBuffer - pointer to pointer of the actual header to be returned in.
  1566. lpdwBufferLength - OUT: if successful, length of output buffer, minus 1
  1567. for any trailing EOS, or if the buffer is not
  1568. large enough, the size required
  1569. dwIndex - a index of which header we're asking for, as there can be multiple headers
  1570. under the same name.
  1571. Arguments:
  1572. lpBase - base for offset HEADER_STRINGs
  1573. lpszHeaderName - pointer to header name
  1574. dwHeaderNameLength - length of header name
  1575. dwModifiers - flags which modify returned value
  1576. lpBuffer - pointer to buffer for results
  1577. lpdwBufferLength - IN: length of lpBuffer
  1578. OUT: length of results, or required length of lpBuffer
  1579. lpdwIndex - IN: 0-based index of header to find
  1580. OUT: next header index if success returned
  1581. Return Value:
  1582. DWORD
  1583. Success - ERROR_SUCCESS
  1584. Failure - ERROR_INSUFFICIENT_BUFFER
  1585. *lpdwBufferLength contains the amount required
  1586. ERROR_HTTP_HEADER_NOT_FOUND
  1587. The specified header (or index of header) was not found
  1588. --*/
  1589. {
  1590. DEBUG_ENTER((DBG_HTTP,
  1591. Dword,
  1592. "HTTP_HEADERS::FastFindHeader",
  1593. "%q, %#x, %#x [%#x], %u",
  1594. GlobalKnownHeaders[dwQueryIndex].Text,
  1595. lplpBuffer,
  1596. lpdwBufferLength,
  1597. *lpdwBufferLength,
  1598. dwIndex
  1599. ));
  1600. PERF_ENTER(FindHeader);
  1601. DWORD error = ERROR_HTTP_HEADER_NOT_FOUND;
  1602. HEADER_STRING * curHeader;
  1603. DWORD dwSlot;
  1604. dwSlot = FastFind(dwQueryIndex, dwIndex);
  1605. if ( dwSlot != INVALID_HEADER_SLOT)
  1606. {
  1607. //
  1608. // found the header - get to the value
  1609. //
  1610. DWORD stringLen;
  1611. LPSTR value;
  1612. curHeader = GetSlot(dwSlot);
  1613. //
  1614. // get a pointer to the value string
  1615. //
  1616. value = curHeader->StringAddress(lpBase) + (GlobalKnownHeaders[dwQueryIndex].Length+1);
  1617. stringLen = curHeader->StringLength() - (GlobalKnownHeaders[dwQueryIndex].Length+1);
  1618. //
  1619. // find the first non-space character in the value.
  1620. //
  1621. // N.B.: Servers can return empty headers, so we may end up with a
  1622. // zero length string
  1623. //
  1624. while ((stringLen > 0) && (*value == ' '))
  1625. {
  1626. ++value;
  1627. --stringLen;
  1628. }
  1629. //
  1630. // get the data in the format requested by the app
  1631. //
  1632. //
  1633. // error is no longer ERROR_HTTP_HEADER_NOT_FOUND, but it might not
  1634. // really be success either...
  1635. //
  1636. error = ERROR_SUCCESS;
  1637. *lplpBuffer = (LPVOID)value;
  1638. *lpdwBufferLength = stringLen;
  1639. }
  1640. PERF_LEAVE(FindHeader);
  1641. DEBUG_LEAVE(error);
  1642. return error;
  1643. }
  1644. DWORD
  1645. HTTP_HEADERS::QueryRawHeaders(
  1646. IN LPSTR lpBase,
  1647. IN BOOL bCrLfTerminated,
  1648. IN LPVOID lpBuffer,
  1649. IN OUT LPDWORD lpdwBufferLength
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. Returns all the request or response headers in a single buffer. The headers
  1654. can be returned as ASCIIZ strings, or CR-LF terminated strings
  1655. Arguments:
  1656. lpBase - base address of strings
  1657. bCrLfTerminated - TRUE if each string is terminated with CR-LF
  1658. lpBuffer - pointer to buffer to write headers
  1659. lpdwBufferLength - IN: length of lpBuffer
  1660. OUT: if successful, length of output buffer, minus 1
  1661. for any trailing EOS, or if the buffer is not
  1662. large enough, the size required
  1663. Return Value:
  1664. DWORD
  1665. Success - ERROR_SUCCESS
  1666. Failure - ERROR_INSUFFICIENT_BUFFER
  1667. ERROR_NOT_ENOUGH_MEMORY
  1668. Ran out of memory trying to acquire lock
  1669. --*/
  1670. {
  1671. PERF_ENTER(QueryRawHeaders);
  1672. DWORD error = ERROR_SUCCESS;
  1673. DWORD requiredLength = 0;
  1674. LPSTR lpszBuffer = (LPSTR)lpBuffer;
  1675. if (!LockHeaders())
  1676. {
  1677. error = ERROR_NOT_ENOUGH_MEMORY;
  1678. goto quit;
  1679. }
  1680. for (DWORD i = 0; i < _TotalSlots; ++i) {
  1681. if (_lpHeaders[i].HaveString()) {
  1682. DWORD length;
  1683. length = _lpHeaders[i].StringLength();
  1684. requiredLength += length + (bCrLfTerminated ? 2 : 1);
  1685. if (*lpdwBufferLength > requiredLength) {
  1686. _lpHeaders[i].CopyTo(lpBase, lpszBuffer);
  1687. lpszBuffer += length;
  1688. if (bCrLfTerminated) {
  1689. *lpszBuffer++ = '\r';
  1690. *lpszBuffer++ = '\n';
  1691. } else {
  1692. *lpszBuffer++ = '\0';
  1693. }
  1694. }
  1695. }
  1696. }
  1697. if (bCrLfTerminated)
  1698. {
  1699. requiredLength += 2;
  1700. if (*lpdwBufferLength > requiredLength)
  1701. {
  1702. *lpszBuffer++ = '\r';
  1703. *lpszBuffer++ = '\n';
  1704. }
  1705. }
  1706. UnlockHeaders();
  1707. ++requiredLength;
  1708. if (*lpdwBufferLength < requiredLength) {
  1709. error = ERROR_INSUFFICIENT_BUFFER;
  1710. } else {
  1711. *lpszBuffer = '\0';
  1712. --requiredLength; // remove 1 for trailing '\0'
  1713. }
  1714. *lpdwBufferLength = requiredLength;
  1715. quit:
  1716. PERF_LEAVE(QueryRawHeaders);
  1717. return error;
  1718. }
  1719. DWORD
  1720. HTTP_HEADERS::QueryFilteredRawHeaders(
  1721. IN LPSTR lpBase,
  1722. IN LPSTR *lplpFilterList,
  1723. IN DWORD cListElements,
  1724. IN BOOL fExclude,
  1725. IN BOOL fSkipVerb,
  1726. IN BOOL bCrLfTerminated,
  1727. IN LPVOID lpBuffer,
  1728. IN OUT LPDWORD lpdwBufferLength
  1729. )
  1730. /*++
  1731. Routine Description:
  1732. Returns all the request or response headers in a single buffer. The headers
  1733. can be returned as ASCIIZ strings, or CR-LF terminated strings
  1734. Arguments:
  1735. lpBase - base address of strings
  1736. bCrLfTerminated - TRUE if each string is terminated with CR-LF
  1737. lpBuffer - pointer to buffer to write headers
  1738. lpdwBufferLength - IN: length of lpBuffer
  1739. OUT: if successful, length of output buffer, minus 1
  1740. for any trailing EOS, or if the buffer is not
  1741. large enough, the size required
  1742. Return Value:
  1743. DWORD
  1744. Success - ERROR_SUCCESS
  1745. Failure - ERROR_INSUFFICIENT_BUFFER
  1746. --*/
  1747. {
  1748. DWORD error = ERROR_NOT_SUPPORTED;
  1749. DWORD requiredLength = 0;
  1750. LPSTR lpszBuffer = (LPSTR)lpBuffer;
  1751. BOOL fCopy;
  1752. DWORD i = fSkipVerb ? 1 : 0;
  1753. for (; i < _TotalSlots; ++i) {
  1754. if (_lpHeaders[i].HaveString()) {
  1755. fCopy = TRUE;
  1756. if (lplpFilterList
  1757. && FMatchList(lplpFilterList, cListElements, _lpHeaders+i, lpBase)) {
  1758. fCopy = fExclude?FALSE:TRUE;
  1759. }
  1760. if (fCopy) {
  1761. DWORD length;
  1762. length = _lpHeaders[i].StringLength();
  1763. requiredLength += length + (bCrLfTerminated ? 2 : 1);
  1764. if (*lpdwBufferLength > requiredLength) {
  1765. _lpHeaders[i].CopyTo(lpBase, lpszBuffer);
  1766. lpszBuffer += length;
  1767. if (bCrLfTerminated) {
  1768. *lpszBuffer++ = '\r';
  1769. *lpszBuffer++ = '\n';
  1770. } else {
  1771. *lpszBuffer++ = '\0';
  1772. }
  1773. }
  1774. }
  1775. }
  1776. }
  1777. if (bCrLfTerminated)
  1778. {
  1779. requiredLength += 2;
  1780. if (*lpdwBufferLength > requiredLength)
  1781. {
  1782. *lpszBuffer++ = '\r';
  1783. *lpszBuffer++ = '\n';
  1784. }
  1785. }
  1786. ++requiredLength;
  1787. if (*lpdwBufferLength < requiredLength) {
  1788. error = ERROR_INSUFFICIENT_BUFFER;
  1789. } else {
  1790. *lpszBuffer = '\0';
  1791. --requiredLength; // remove 1 for trailing '\0'
  1792. error = ERROR_SUCCESS;
  1793. }
  1794. *lpdwBufferLength = requiredLength;
  1795. return error;
  1796. }
  1797. DWORD
  1798. HTTP_HEADERS::AddRequest(
  1799. IN LPSTR lpszVerb,
  1800. IN LPSTR lpszObject,
  1801. IN LPSTR lpszVersion
  1802. )
  1803. /*++
  1804. Routine Description:
  1805. Builds the request line from its constituent parts. The request line is the
  1806. first (0th) header in the request headers
  1807. Assumes: 1. This is the one-and-only call to this method
  1808. 2. lpszObject must already be escaped if necessary
  1809. Arguments:
  1810. lpszVerb - pointer to HTTP verb, e.g. "GET"
  1811. lpszObject - pointer to HTTP object name, e.g. "/users/albert/~emc2.htm".
  1812. lpszVersion - pointer to HTTP version string, e.g. "HTTP/1.0"
  1813. Return Value:
  1814. DWORD
  1815. Success - ERROR_SUCCESS
  1816. Failure - ERROR_NOT_ENOUGH_MEMORY
  1817. --*/
  1818. {
  1819. PERF_ENTER(AddRequest);
  1820. //
  1821. // there must not be a header when this method is called
  1822. //
  1823. INET_ASSERT(_HeadersLength == 0);
  1824. DWORD error = ERROR_SUCCESS;
  1825. int verbLen = lstrlen(lpszVerb);
  1826. int objectLen = lstrlen(lpszObject);
  1827. int versionLen = lstrlen(lpszVersion);
  1828. int len = verbLen // "GET"
  1829. + 1 // ' '
  1830. + objectLen // "/users/albert/~emc2.htm"
  1831. + 1 // ' '
  1832. + versionLen // "HTTP/1.0"
  1833. + 1 // '\0'
  1834. ;
  1835. //
  1836. // we are about to start updating the headers for the current
  1837. // HTTP_REQUEST_HANDLE_OBJECT. Serialize access
  1838. //
  1839. HEADER_STRING * pRequest = GetFirstHeader();
  1840. HEADER_STRING & request = *pRequest;
  1841. if (pRequest == NULL) {
  1842. error = ERROR_NOT_ENOUGH_MEMORY;
  1843. goto quit;
  1844. }
  1845. INET_ASSERT(!request.HaveString());
  1846. _lpszVerb = NULL;
  1847. _dwVerbLength = 0;
  1848. _lpszObjectName = NULL;
  1849. _dwObjectNameLength = 0;
  1850. _lpszVersion = NULL;
  1851. _dwVersionLength = 0;
  1852. request.CreateStringBuffer((LPVOID)lpszVerb, verbLen, len);
  1853. if (request.IsError()) {
  1854. error = GetLastError();
  1855. INET_ASSERT(error != ERROR_SUCCESS);
  1856. } else {
  1857. request += ' ';
  1858. request.Strncat((LPVOID)lpszObject, objectLen);
  1859. request += ' ';
  1860. request.Strncat((LPVOID)lpszVersion, versionLen);
  1861. _HeadersLength = len - 1 + (sizeof("\r\n") - 1);
  1862. //
  1863. // we have used the first free slot in the headers array
  1864. //
  1865. --_FreeSlots;
  1866. //
  1867. // update the component variables in case of a ModifyRequest()
  1868. //
  1869. _lpszVerb = request.StringAddress();
  1870. _dwVerbLength = verbLen;
  1871. _lpszObjectName = _lpszVerb + verbLen + 1;
  1872. _dwObjectNameLength = objectLen;
  1873. _lpszVersion = _lpszObjectName + objectLen + 1;
  1874. _dwVersionLength = versionLen;
  1875. SetRequestVersion();
  1876. error = request.IsError() ? ::GetLastError() : ERROR_SUCCESS;
  1877. }
  1878. quit:
  1879. PERF_LEAVE(AddRequest);
  1880. return error;
  1881. }
  1882. DWORD
  1883. HTTP_HEADERS::ModifyRequest(
  1884. IN HTTP_METHOD_TYPE tMethod,
  1885. IN LPSTR lpszObjectName,
  1886. IN DWORD dwObjectNameLength,
  1887. IN LPSTR lpszVersion OPTIONAL,
  1888. IN DWORD dwVersionLength
  1889. )
  1890. /*++
  1891. Routine Description:
  1892. Updates the request line. Used in redirection
  1893. Arguments:
  1894. tMethod - type of new method
  1895. lpszObjectName - pointer to new object name
  1896. dwObjectNameLength - length of new object name
  1897. lpszVersion - optional pointer to version string
  1898. dwVersionLength - length of lpszVersion string if present
  1899. Return Value:
  1900. DWORD
  1901. Success - ERROR_SUCCESS
  1902. Failure - ERROR_NOT_ENOUGH_MEMORY
  1903. --*/
  1904. {
  1905. DEBUG_ENTER((DBG_HTTP,
  1906. Dword,
  1907. "ModifyRequest",
  1908. "%s, %q, %d, %q, %d",
  1909. MapHttpMethodType(tMethod),
  1910. lpszObjectName,
  1911. dwObjectNameLength,
  1912. lpszVersion,
  1913. dwVersionLength
  1914. ));
  1915. PERF_ENTER(ModifyRequest);
  1916. INET_ASSERT(lpszObjectName != NULL);
  1917. INET_ASSERT(dwObjectNameLength != 0);
  1918. //
  1919. // there must already be a header when this method is called
  1920. //
  1921. INET_ASSERT(_HeadersLength != 0);
  1922. //
  1923. // we are about to start updating the headers for the current
  1924. // HTTP_REQUEST_HANDLE_OBJECT. Serialize access
  1925. //
  1926. //
  1927. // BUGBUG [arthurbi] using two HEADER_STRINGs here causes an extra
  1928. // ReAlloc when use the Copy operator between the two.
  1929. //
  1930. HEADER_STRING * pRequest = GetFirstHeader();
  1931. HEADER_STRING & request = *pRequest;
  1932. HEADER_STRING newRequest;
  1933. LPCSTR lpcszVerb;
  1934. DWORD verbLength;
  1935. DWORD error = ERROR_SUCCESS;
  1936. DWORD length;
  1937. //
  1938. // there must already be a request line
  1939. //
  1940. if (pRequest == NULL) {
  1941. error = ERROR_NOT_ENOUGH_MEMORY;
  1942. goto quit;
  1943. }
  1944. INET_ASSERT(request.HaveString());
  1945. //
  1946. // get the verb/method to use.
  1947. //
  1948. if (tMethod == HTTP_METHOD_TYPE_UNKNOWN) {
  1949. //
  1950. // the method is unknown, read the old one out of the string
  1951. // and save off, basically we're reusing the previous one.
  1952. //
  1953. lpcszVerb = request.StringAddress();
  1954. for (DWORD i = 0; i < request.StringLength(); i++) {
  1955. if (lpcszVerb[i] == ' ') {
  1956. break;
  1957. }
  1958. }
  1959. INET_ASSERT((i > 0) && (i < (DWORD)request.StringLength()));
  1960. verbLength = (DWORD)i;
  1961. } else {
  1962. //
  1963. // its one of the normal kind, just map it.
  1964. //
  1965. verbLength = MapHttpMethodType(tMethod, &lpcszVerb);
  1966. }
  1967. if (lpszVersion == NULL) {
  1968. lpszVersion = _lpszVersion;
  1969. dwVersionLength = _dwVersionLength;
  1970. }
  1971. _lpszVerb = NULL;
  1972. _dwVerbLength = 0;
  1973. _lpszObjectName = NULL;
  1974. _dwObjectNameLength = 0;
  1975. _lpszVersion = NULL;
  1976. _dwVersionLength = 0;
  1977. //
  1978. // calculate the new length from the component lengths we originally set
  1979. // in AddRequest(), and the new object name
  1980. //
  1981. length = verbLength + 1 + dwObjectNameLength + 1 + dwVersionLength + 1;
  1982. //
  1983. // create a new request line
  1984. //
  1985. newRequest.CreateStringBuffer((LPVOID)lpcszVerb, verbLength, length);
  1986. if (newRequest.IsError()) {
  1987. error = GetLastError();
  1988. } else {
  1989. newRequest += ' ';
  1990. newRequest.Strncat((LPVOID)lpszObjectName, dwObjectNameLength);
  1991. newRequest += ' ';
  1992. newRequest.Strncat((LPVOID)lpszVersion, dwVersionLength);
  1993. //
  1994. // remove the current request line length from the header buffer
  1995. // aggregate
  1996. //
  1997. _HeadersLength -= request.StringLength();
  1998. //
  1999. // make the current request line the new one
  2000. //
  2001. request = newRequest.StringAddress();
  2002. //
  2003. // and update the address and length variables (version length is the
  2004. // only thing that stays the same)
  2005. //
  2006. if (!request.IsError()) {
  2007. _lpszVerb = request.StringAddress();
  2008. _dwVerbLength = verbLength;
  2009. _lpszObjectName = _lpszVerb + verbLength + 1;
  2010. _dwObjectNameLength = dwObjectNameLength;
  2011. _lpszVersion = _lpszObjectName + dwObjectNameLength + 1;
  2012. _dwVersionLength = dwVersionLength;
  2013. SetRequestVersion();
  2014. //
  2015. // and the new request line length to the aggregate header length
  2016. //
  2017. _HeadersLength += request.StringLength();
  2018. } else {
  2019. error = GetLastError();
  2020. }
  2021. }
  2022. quit:
  2023. PERF_LEAVE(ModifyRequest);
  2024. DEBUG_LEAVE(error);
  2025. return error;
  2026. }
  2027. VOID
  2028. HTTP_HEADERS::SetRequestVersion(
  2029. VOID
  2030. )
  2031. /*++
  2032. Routine Description:
  2033. Set _RequestVersionMajor and _RequestVersionMinor based on the HTTP
  2034. version string
  2035. Arguments:
  2036. None.
  2037. Return Value:
  2038. None.
  2039. --*/
  2040. {
  2041. DEBUG_ENTER((DBG_HTTP,
  2042. None,
  2043. "HTTP_HEADERS::SetRequestVersion",
  2044. NULL
  2045. ));
  2046. INET_ASSERT(_lpszVersion != NULL);
  2047. _RequestVersionMajor = 0;
  2048. _RequestVersionMinor = 0;
  2049. if (strncmp(_lpszVersion, "HTTP/", sizeof("HTTP/") - 1) == 0) {
  2050. LPSTR pNum = _lpszVersion + sizeof("HTTP/") - 1;
  2051. ExtractInt(&pNum, 0, (LPINT)&_RequestVersionMajor);
  2052. while (!isdigit(*pNum) && (*pNum != '\0')) {
  2053. ++pNum;
  2054. }
  2055. ExtractInt(&pNum, 0, (LPINT)&_RequestVersionMinor);
  2056. DEBUG_PRINT(HTTP,
  2057. INFO,
  2058. ("request version = %d.%d\n",
  2059. _RequestVersionMajor,
  2060. _RequestVersionMinor
  2061. ));
  2062. } else {
  2063. DEBUG_PRINT(HTTP,
  2064. WARNING,
  2065. ("\"HTTP/\" not found in %q\n",
  2066. _lpszVersion
  2067. ));
  2068. }
  2069. DEBUG_LEAVE(0);
  2070. }