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.

944 lines
27 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. query.cxx
  5. Abstract:
  6. This file contains the implementation of the HttpQueryInfoA API.
  7. Contents:
  8. HttpQueryInfoA
  9. WinHttpQueryHeaders
  10. HTTP_REQUEST_HANDLE_OBJECT::QueryInfo
  11. Author:
  12. Keith Moore (keithmo) 16-Nov-1994
  13. Revision History:
  14. Modified to make HttpQueryInfoA remotable. madana (2/8/95)
  15. --*/
  16. #include <wininetp.h>
  17. #include "httpp.h"
  18. //
  19. // private prototypes
  20. //
  21. //
  22. // private data
  23. //
  24. #define NUM_HEADERS ARRAY_ELEMENTS(GlobalKnownHeaders)
  25. //
  26. // functions
  27. //
  28. INTERNETAPI
  29. BOOL
  30. WINAPI
  31. HttpQueryInfoA(
  32. IN HINTERNET hRequest,
  33. IN DWORD dwInfoLevel,
  34. IN LPCSTR lpszName OPTIONAL,
  35. IN OUT LPVOID lpBuffer OPTIONAL,
  36. IN OUT LPDWORD lpdwBufferLength,
  37. IN OUT LPDWORD lpdwIndex OPTIONAL
  38. )
  39. /*++
  40. Routine Description:
  41. Queries a request or response header from the HTTP request handle
  42. Arguments:
  43. hRequest - an open HTTP request handle returned by
  44. HttpOpenRequest()
  45. dwInfoLevel - one of the HTTP_QUERY_* values indicating the
  46. attribute to query. In addition, the following flags
  47. can be set:
  48. HTTP_QUERY_FLAG_REQUEST_HEADERS
  49. - Causes the request headers to be queried. The
  50. default is to check the response headers
  51. HTTP_QUERY_FLAG_SYSTEMTIME
  52. - Causes headers that contain date & time
  53. information to be returned as SYSTEMTIME
  54. structures
  55. HTTP_QUERY_FLAG_NUMBER
  56. - Causes header value to be returned as a number.
  57. Useful for when the app knows it is expecting
  58. a numeric value, e.g. status code
  59. lpBuffer - pointer to the buffer to receive the information.
  60. If dwInfoLevel is HTTP_QUERY_CUSTOM then buffer
  61. contains the header to query.
  62. If NULL then we just return the required buffer length
  63. to hold the header specified by dwInfoLevel
  64. lpdwBufferLength - IN: contains the length (in BYTEs) of lpBuffer
  65. OUT: size of data written to lpBuffer, or required
  66. buffer length if ERROR_INSUFFICIENT_BUFFER
  67. returned
  68. lpdwIndex - IN: 0-based header index
  69. OUT: next index to query, if success returned
  70. Return Value:
  71. TRUE - The query succeeded. lpBuffer contains the query information, and
  72. *lpdwBufferLength contains the size (in BYTEs) of the information
  73. FALSE - The operation failed. Error status is available by calling
  74. GetLastError().
  75. --*/
  76. {
  77. DEBUG_ENTER_API((DBG_API,
  78. Bool,
  79. "HttpQueryInfoA",
  80. "%#x, %s (%#x), %#x [%q], %#x [%d], %#x [%d]",
  81. hRequest,
  82. InternetMapHttpOption(dwInfoLevel & HTTP_QUERY_HEADER_MASK),
  83. dwInfoLevel,
  84. lpBuffer,
  85. ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
  86. ? lpBuffer
  87. : "",
  88. lpdwBufferLength,
  89. lpdwBufferLength ? *lpdwBufferLength : 0,
  90. lpdwIndex,
  91. lpdwIndex ? *lpdwIndex : 0
  92. ));
  93. DWORD defaultIndex = 0;
  94. DWORD error;
  95. HINTERNET hRequestMapped = NULL;
  96. if (!GlobalDataInitialized) {
  97. error = ERROR_WINHTTP_NOT_INITIALIZED;
  98. goto done;
  99. }
  100. //
  101. // get the thread info
  102. //
  103. LPINTERNET_THREAD_INFO lpThreadInfo;
  104. lpThreadInfo = InternetGetThreadInfo();
  105. if (lpThreadInfo == NULL) {
  106. error = ERROR_WINHTTP_INTERNAL_ERROR;
  107. goto done;
  108. }
  109. _InternetIncNestingCount();
  110. //
  111. // map the handle
  112. //
  113. error = MapHandleToAddress(hRequest, (LPVOID *)&hRequestMapped, FALSE);
  114. if (error != ERROR_SUCCESS) {
  115. goto quit;
  116. }
  117. //
  118. // find path from Internet handle
  119. //
  120. BOOL isLocal;
  121. BOOL isAsync;
  122. error = RIsHandleLocal(hRequestMapped,
  123. &isLocal,
  124. &isAsync,
  125. TypeHttpRequestHandle
  126. );
  127. if (error != ERROR_SUCCESS) {
  128. goto quit;
  129. }
  130. //
  131. // validate parameters
  132. //
  133. DWORD queryModifiers;
  134. DWORD infoLevel;
  135. queryModifiers = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
  136. infoLevel = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
  137. if (((infoLevel > HTTP_QUERY_MAX) && (infoLevel != HTTP_QUERY_CUSTOM))
  138. || (lpdwBufferLength == NULL)
  139. //
  140. // nip in the bud apps that want SYSTEMTIME AND NUMBER for same header(!)
  141. //
  142. #define EXCLUSIVE_MODIFIERS (HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_FLAG_SYSTEMTIME)
  143. || ((dwInfoLevel & EXCLUSIVE_MODIFIERS) == EXCLUSIVE_MODIFIERS)) {
  144. error = ERROR_INVALID_PARAMETER;
  145. goto quit;
  146. }
  147. //
  148. // if the app passed in a NULL lpdwIndex then it is asking for index 0
  149. //
  150. if (!ARGUMENT_PRESENT(lpdwIndex)) {
  151. lpdwIndex = &defaultIndex;
  152. }
  153. //
  154. // if the app is asking for one of the special query items - status code,
  155. // status text, HTTP version, or one of the raw header variants, then make
  156. // sure the index is 0. These pseudo-header types cannot be enumerated
  157. //
  158. if ((*lpdwIndex != 0)
  159. && ((infoLevel == HTTP_QUERY_VERSION)
  160. || (infoLevel == HTTP_QUERY_STATUS_CODE)
  161. || (infoLevel == HTTP_QUERY_STATUS_TEXT)
  162. || (infoLevel == HTTP_QUERY_RAW_HEADERS)
  163. || (infoLevel == HTTP_QUERY_RAW_HEADERS_CRLF))) {
  164. error = ERROR_HTTP_HEADER_NOT_FOUND;
  165. goto quit;
  166. }
  167. //
  168. // ensure that we can use any flags passed in
  169. //
  170. if (infoLevel == HTTP_QUERY_CUSTOM) {
  171. //
  172. // the app has given us a string to locate. We only accept strings in
  173. // the following format:
  174. //
  175. // <header-to-find>[:][CR][LF]<EOS>
  176. //
  177. // The header cannot contain any spaces
  178. //
  179. INET_ASSERT(error == ERROR_SUCCESS);
  180. int queryLength = 0;
  181. int headerLength = 0;
  182. for (; lpszName[queryLength] != '\0'; ++queryLength) {
  183. if ((lpszName[queryLength] == ':')
  184. || (lpszName[queryLength] == '\r')
  185. || (lpszName[queryLength] == '\n')) {
  186. break;
  187. }
  188. if (iscntrl(lpszName[queryLength])
  189. || isspace(lpszName[queryLength])) {
  190. error = ERROR_INVALID_PARAMETER;
  191. break;
  192. }
  193. }
  194. } else if ((queryModifiers & ~GlobalKnownHeaders[infoLevel].Flags) != 0) {
  195. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  196. }
  197. if (error != ERROR_SUCCESS) {
  198. goto quit;
  199. }
  200. //
  201. // if NULL buffer pointer then app wants length of option: set buffer length
  202. // to zero
  203. //
  204. if (!ARGUMENT_PRESENT(lpBuffer)) {
  205. *lpdwBufferLength = 0;
  206. }
  207. INET_ASSERT(error == ERROR_SUCCESS);
  208. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  209. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequestMapped;
  210. if (dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) {
  211. if (!IS_VALID_HTTP_STATE(pRequest, QUERY_REQUEST, TRUE)) {
  212. error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
  213. }
  214. } else {
  215. if (!IS_VALID_HTTP_STATE(pRequest, QUERY_RESPONSE, TRUE)) {
  216. error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
  217. }
  218. }
  219. if (error == ERROR_SUCCESS) {
  220. error = pRequest->QueryInfo(dwInfoLevel,
  221. lpszName,
  222. lpBuffer,
  223. lpdwBufferLength,
  224. lpdwIndex
  225. );
  226. }
  227. quit:
  228. _InternetDecNestingCount(1);
  229. done:
  230. BOOL success;
  231. if (error != ERROR_SUCCESS) {
  232. DEBUG_ERROR(HTTP, error);
  233. SetLastError(error);
  234. success = FALSE;
  235. } else {
  236. DEBUG_PRINT_API(API,
  237. INFO,
  238. ("*lpdwBufferLength = %d\n",
  239. *lpdwBufferLength
  240. ));
  241. DEBUG_DUMP_API(DUMP_API_DATA,
  242. "Query data:\n",
  243. lpBuffer,
  244. *lpdwBufferLength
  245. );
  246. success = TRUE;
  247. }
  248. if (hRequestMapped != NULL) {
  249. DereferenceObject((LPVOID)hRequestMapped);
  250. }
  251. DEBUG_LEAVE_API(success);
  252. return success;
  253. }
  254. INTERNETAPI
  255. BOOL
  256. WINAPI
  257. WinHttpQueryHeaders(
  258. IN HINTERNET hRequest,
  259. IN DWORD dwInfoLevel,
  260. IN LPCWSTR lpszName OPTIONAL,
  261. OUT LPVOID lpBuffer OPTIONAL,
  262. IN OUT LPDWORD lpdwBufferLength,
  263. IN OUT LPDWORD lpdwIndex OPTIONAL
  264. )
  265. /*++
  266. Routine Description:
  267. Queries information from the HTTP request handle.
  268. Arguments:
  269. hHttpRequest - An open HTTP request handle returned by HttpOpenRequest().
  270. dwInfoLevel - One of the HTTP_QUERY_* values indicating the attribute
  271. to query.
  272. lpBuffer - Pointer to the buffer to receive the information.
  273. dwBufferLength - On entry, contains the length (in BYTEs) of the data
  274. buffer. On exit, contains the size (in BYTEs) of the data written
  275. to lpBuffer.
  276. Return Value:
  277. TRUE - The query succeeded. lpBuffer contains the query information,
  278. and lpBufferLength contains the size (in BYTEs) of the information.
  279. FALSE - The operation failed. Error status is available by calling
  280. GetLastError().
  281. Comments:
  282. --*/
  283. {
  284. DEBUG_ENTER_API((DBG_API,
  285. Bool,
  286. "WinHttpQueryHeaders",
  287. "%#x, %s (%#x), %wq, %#x, %#x [%d], %#x [%d]",
  288. hRequest,
  289. InternetMapHttpOption(dwInfoLevel & HTTP_QUERY_HEADER_MASK),
  290. dwInfoLevel,
  291. lpszName? lpszName : L"<null>",
  292. lpBuffer,
  293. lpdwBufferLength,
  294. lpdwBufferLength ? *lpdwBufferLength : 0,
  295. lpdwIndex,
  296. lpdwIndex ? *lpdwIndex : 0
  297. ));
  298. DWORD dwErr = ERROR_SUCCESS;
  299. BOOL fResult=FALSE;
  300. INET_ASSERT(hRequest);
  301. MEMORYPACKET mpBuffer, mpName;
  302. if (!lpdwBufferLength
  303. || IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
  304. || (lpBuffer && ProbeWriteBuffer(lpBuffer, *lpdwBufferLength))
  305. || (lpdwIndex && IsBadWritePtr(lpdwIndex, sizeof(*lpdwIndex))))
  306. {
  307. dwErr = ERROR_INVALID_PARAMETER;
  308. goto cleanup;
  309. }
  310. if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
  311. {
  312. if (!lpszName
  313. || IsBadStringPtrW(lpszName, -1))
  314. {
  315. dwErr = ERROR_INVALID_PARAMETER;
  316. goto cleanup;
  317. }
  318. ALLOC_MB(lpszName,0,mpName);
  319. if (!mpName.psStr)
  320. {
  321. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  322. goto cleanup;
  323. }
  324. UNICODE_TO_ANSI(lpszName,mpName);
  325. }
  326. if (lpBuffer)
  327. {
  328. mpBuffer.dwAlloc = mpBuffer.dwSize = *lpdwBufferLength;
  329. mpBuffer.psStr = (LPSTR)ALLOC_BYTES(mpBuffer.dwAlloc*sizeof(CHAR));
  330. if (!mpBuffer.psStr)
  331. {
  332. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  333. goto cleanup;
  334. }
  335. }
  336. fResult = HttpQueryInfoA(hRequest,dwInfoLevel, mpName.psStr,
  337. mpBuffer.psStr, &mpBuffer.dwSize, lpdwIndex);
  338. if (!((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
  339. (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)))
  340. {
  341. // This is the default, we've been handed back a string.
  342. if (fResult)
  343. {
  344. *lpdwBufferLength = MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize + 1,
  345. NULL, 0);
  346. *lpdwBufferLength *= sizeof(WCHAR);
  347. if (*lpdwBufferLength<=mpBuffer.dwAlloc)
  348. {
  349. MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize+1,
  350. (LPWSTR)lpBuffer, mpBuffer.dwAlloc/sizeof(WCHAR));
  351. *lpdwBufferLength -= sizeof(WCHAR);
  352. }
  353. else
  354. {
  355. fResult = FALSE;
  356. dwErr = ERROR_INSUFFICIENT_BUFFER;
  357. }
  358. }
  359. else
  360. {
  361. if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
  362. {
  363. *lpdwBufferLength = mpBuffer.dwSize*sizeof(WCHAR);
  364. }
  365. }
  366. }
  367. else
  368. {
  369. if (fResult)
  370. {
  371. memcpy(lpBuffer, (LPVOID)mpBuffer.psStr, mpBuffer.dwSize);
  372. }
  373. *lpdwBufferLength = mpBuffer.dwSize;
  374. }
  375. cleanup:
  376. if (dwErr!=ERROR_SUCCESS)
  377. {
  378. SetLastError(dwErr);
  379. DEBUG_ERROR(HTTP, dwErr);
  380. }
  381. DEBUG_LEAVE_API(fResult);
  382. return fResult;
  383. }
  384. //
  385. // object methods
  386. //
  387. DWORD
  388. HTTP_REQUEST_HANDLE_OBJECT::QueryInfo(
  389. IN DWORD dwInfoLevel,
  390. IN LPCSTR headerName,
  391. OUT LPVOID lpBuffer OPTIONAL,
  392. IN OUT LPDWORD lpdwBufferLength,
  393. IN OUT LPDWORD lpdwIndex
  394. )
  395. /*++
  396. Routine Description:
  397. Header query method for HTTP_REQUEST_HANDLE_OBJECT class
  398. Arguments:
  399. dwInfoLevel - level of info (header) to get
  400. headerName - name of header with HTTP_QUERY_CUSTOM
  401. lpBuffer - pointer to user's buffer
  402. lpdwBufferLength - IN: length of user's buffer
  403. OUT: length of returned information or required buffer
  404. length if insufficient
  405. lpdwIndex - IN: 0-based index of named header to return
  406. OUT: index of next header if success returned
  407. Return Value:
  408. DWORD
  409. Success - ERROR_SUCCESS
  410. Failure - ERROR_HTTP_HEADER_NOT_FOUND
  411. Couldn't find the requested header
  412. ERROR_HTTP_INVALID_QUERY_REQUEST
  413. The caller asked for e.g. the Accept: header to be returned
  414. as a SYSTEMTIME structure, or for e.g. a request header that
  415. only exists for response headers (status code, for example)
  416. ERROR_INSUFFICIENT_BUFFER
  417. User's buffer not large enough to hold requested data
  418. --*/
  419. {
  420. INET_ASSERT(lpdwBufferLength != NULL);
  421. INET_ASSERT(lpdwIndex != NULL);
  422. DWORD error;
  423. DWORD headerNameLength;
  424. DWORD modifiers;
  425. modifiers = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
  426. dwInfoLevel &= HTTP_QUERY_HEADER_MASK;
  427. if (dwInfoLevel == HTTP_QUERY_CUSTOM) {
  428. for (headerNameLength = 0; ; ++headerNameLength) {
  429. if ((headerName[headerNameLength] == '\0')
  430. || (headerName[headerNameLength] == ':')
  431. || (headerName[headerNameLength] == '\r')
  432. || (headerName[headerNameLength] == '\n')) {
  433. break;
  434. }
  435. }
  436. } else if (dwInfoLevel == HTTP_QUERY_REQUEST_METHOD) {
  437. LPSTR lpszVerb;
  438. DWORD dwVerbLength;
  439. lpszVerb = _RequestHeaders.GetVerb(&dwVerbLength);
  440. if ((lpszVerb != NULL) && (dwVerbLength != 0)) {
  441. //
  442. // the verb is (usually) space terminated
  443. //
  444. while ((dwVerbLength > 0) && (lpszVerb[dwVerbLength - 1] == ' ')) {
  445. --dwVerbLength;
  446. }
  447. //
  448. // *lpdwBufferLength will be 0 if lpBuffer is NULL
  449. //
  450. if (*lpdwBufferLength > dwVerbLength) {
  451. memcpy(lpBuffer, lpszVerb, dwVerbLength);
  452. ((LPBYTE)lpBuffer)[dwVerbLength] = '\0';
  453. error = ERROR_SUCCESS;
  454. } else {
  455. ++dwVerbLength;
  456. error = ERROR_INSUFFICIENT_BUFFER;
  457. }
  458. *lpdwBufferLength = dwVerbLength;
  459. } else {
  460. error = ERROR_HTTP_HEADER_NOT_FOUND;
  461. }
  462. goto quit;
  463. } else {
  464. headerName = GlobalKnownHeaders[dwInfoLevel].Text;
  465. headerNameLength = GlobalKnownHeaders[dwInfoLevel].Length;
  466. }
  467. if (modifiers & HTTP_QUERY_FLAG_REQUEST_HEADERS) {
  468. //
  469. // we can always query request headers, even if the server is down
  470. // level
  471. //
  472. switch (dwInfoLevel) {
  473. case HTTP_QUERY_VERSION:
  474. case HTTP_QUERY_STATUS_CODE:
  475. case HTTP_QUERY_STATUS_TEXT:
  476. //
  477. // can't query these sub-header values from the request headers
  478. //
  479. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  480. break;
  481. case HTTP_QUERY_RAW_HEADERS:
  482. case HTTP_QUERY_RAW_HEADERS_CRLF:
  483. error = _RequestHeaders.QueryRawHeaders(
  484. NULL,
  485. dwInfoLevel == HTTP_QUERY_RAW_HEADERS_CRLF,
  486. lpBuffer,
  487. lpdwBufferLength
  488. );
  489. break;
  490. case HTTP_QUERY_ECHO_HEADERS:
  491. case HTTP_QUERY_ECHO_HEADERS_CRLF:
  492. error = QueryRequestHeadersWithEcho(
  493. dwInfoLevel == HTTP_QUERY_ECHO_HEADERS_CRLF,
  494. lpBuffer,
  495. lpdwBufferLength
  496. );
  497. break;
  498. case HTTP_QUERY_CUSTOM:
  499. if (_RequestHeaders.LockHeaders())
  500. {
  501. error = QueryRequestHeader(headerName,
  502. headerNameLength,
  503. lpBuffer,
  504. lpdwBufferLength,
  505. modifiers,
  506. lpdwIndex
  507. );
  508. _RequestHeaders.UnlockHeaders();
  509. }
  510. else
  511. {
  512. error = ERROR_NOT_ENOUGH_MEMORY;
  513. }
  514. break;
  515. default:
  516. if (_RequestHeaders.LockHeaders())
  517. {
  518. error = QueryRequestHeader( dwInfoLevel,
  519. lpBuffer,
  520. lpdwBufferLength,
  521. modifiers,
  522. lpdwIndex
  523. );
  524. _RequestHeaders.UnlockHeaders();
  525. }
  526. else
  527. {
  528. error = ERROR_NOT_ENOUGH_MEMORY;
  529. }
  530. break;
  531. }
  532. } else if (!IsDownLevel()) {
  533. switch (dwInfoLevel) {
  534. case HTTP_QUERY_VERSION:
  535. error = QueryResponseVersion(lpBuffer, lpdwBufferLength);
  536. break;
  537. case HTTP_QUERY_STATUS_CODE:
  538. error = QueryStatusCode(lpBuffer, lpdwBufferLength, modifiers);
  539. break;
  540. case HTTP_QUERY_STATUS_TEXT:
  541. error = QueryStatusText(lpBuffer, lpdwBufferLength);
  542. break;
  543. case HTTP_QUERY_RAW_HEADERS:
  544. case HTTP_QUERY_RAW_HEADERS_CRLF:
  545. error = _ResponseHeaders.QueryRawHeaders(
  546. (LPSTR)_ResponseBuffer,
  547. dwInfoLevel == HTTP_QUERY_RAW_HEADERS_CRLF,
  548. lpBuffer,
  549. lpdwBufferLength
  550. );
  551. break;
  552. case HTTP_QUERY_ECHO_HEADERS:
  553. case HTTP_QUERY_ECHO_HEADERS_CRLF:
  554. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  555. break;
  556. case HTTP_QUERY_CUSTOM:
  557. if (_RequestHeaders.LockHeaders())
  558. {
  559. error = QueryResponseHeader(
  560. headerName,
  561. headerNameLength,
  562. lpBuffer,
  563. lpdwBufferLength,
  564. modifiers,
  565. lpdwIndex
  566. );
  567. _RequestHeaders.UnlockHeaders();
  568. }
  569. else
  570. {
  571. error = ERROR_NOT_ENOUGH_MEMORY;
  572. }
  573. break;
  574. default:
  575. if (_ResponseHeaders.LockHeaders())
  576. {
  577. error = QueryResponseHeader(
  578. dwInfoLevel,
  579. lpBuffer,
  580. lpdwBufferLength,
  581. modifiers,
  582. lpdwIndex
  583. );
  584. _ResponseHeaders.UnlockHeaders();
  585. }
  586. else
  587. {
  588. error = ERROR_NOT_ENOUGH_MEMORY;
  589. }
  590. break;
  591. }
  592. } else {
  593. //
  594. // there are no response headers from down-level servers
  595. //
  596. error = ERROR_HTTP_HEADER_NOT_FOUND;
  597. }
  598. quit:
  599. return error;
  600. }
  601. DWORD
  602. HTTP_REQUEST_HANDLE_OBJECT::QueryRequestHeadersWithEcho(
  603. IN BOOL bCrlfTerminated,
  604. OUT LPVOID lpBuffer OPTIONAL,
  605. IN OUT LPDWORD lpdwBufferLength
  606. )
  607. /*++
  608. Routine Description:
  609. Header query for request headers with echo headers added if any..
  610. Arguments:
  611. bCrlfTerminated - should the headers be seperated by CRLF's
  612. lpBuffer - pointer to user's buffer
  613. lpdwBufferLength - IN: length of user's buffer
  614. OUT: length of returned information or required buffer
  615. length if insufficient
  616. Return Value:
  617. DWORD
  618. Success - ERROR_SUCCESS
  619. Failure -
  620. ERROR_INSUFFICIENT_BUFFER
  621. User's buffer not large enough to hold requested data
  622. --*/
  623. {
  624. INET_ASSERT(lpdwBufferLength != NULL);
  625. DWORD error;
  626. LPSTR lpszEchoHeaderIn = NULL ;
  627. LPSTR lpszEchoHeaderOut = NULL;
  628. DWORD cbHeaderIn = 0;
  629. DWORD cbHeaderOut = 0;
  630. BOOL bEchoPresent = FALSE;
  631. // List of headers to filter out of the Request headers
  632. LPSTR rglpFilter [ ] =
  633. {
  634. GlobalKnownHeaders[HTTP_QUERY_AUTHORIZATION].Text,
  635. GlobalKnownHeaders[HTTP_QUERY_CONNECTION].Text,
  636. GlobalKnownHeaders[HTTP_QUERY_CONTENT_LENGTH].Text,
  637. GlobalKnownHeaders[HTTP_QUERY_COOKIE].Text,
  638. GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Text,
  639. GlobalKnownHeaders[HTTP_QUERY_HOST].Text,
  640. GlobalKnownHeaders[HTTP_QUERY_IF_MODIFIED_SINCE].Text,
  641. GlobalKnownHeaders[HTTP_QUERY_IF_MATCH].Text,
  642. GlobalKnownHeaders[HTTP_QUERY_IF_NONE_MATCH].Text,
  643. GlobalKnownHeaders[HTTP_QUERY_IF_RANGE].Text,
  644. GlobalKnownHeaders[HTTP_QUERY_IF_UNMODIFIED_SINCE].Text,
  645. GlobalKnownHeaders[HTTP_QUERY_PROXY_AUTHORIZATION].Text,
  646. GlobalKnownHeaders[HTTP_QUERY_PROXY_CONNECTION].Text,
  647. GlobalKnownHeaders[HTTP_QUERY_RANGE].Text,
  648. GlobalKnownHeaders[HTTP_QUERY_UNLESS_MODIFIED_SINCE].Text,
  649. };
  650. if (!_ResponseHeaders.LockHeaders())
  651. {
  652. error = ERROR_NOT_ENOUGH_MEMORY;
  653. goto quit;
  654. }
  655. error = FastQueryResponseHeader(HTTP_QUERY_ECHO_REQUEST,
  656. (LPVOID *)&lpszEchoHeaderIn,
  657. &cbHeaderIn,
  658. 0);
  659. if (error == ERROR_SUCCESS)
  660. {
  661. DWORD cbEchoRequest = GlobalKnownHeaders[HTTP_QUERY_ECHO_REQUEST].Length;
  662. DWORD cbEchoReply = GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Length;
  663. bEchoPresent = TRUE;
  664. // Add echo-reply: to the begining of the header.
  665. cbHeaderOut = cbEchoReply + 1 // For echo-reply:
  666. + cbHeaderIn // Send back the stuff from the header.
  667. + (bCrlfTerminated ? 2 : 1) // 2 for CRLF
  668. + 1; // 1 for NULL terminator
  669. lpszEchoHeaderOut = (LPSTR) _alloca(cbHeaderOut); // Add 1 for null terminator.
  670. if ( lpszEchoHeaderOut == NULL)
  671. {
  672. error = ERROR_NOT_ENOUGH_MEMORY;
  673. goto done;
  674. }
  675. LPSTR lpsz = lpszEchoHeaderOut;
  676. memcpy(lpszEchoHeaderOut, GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Text, cbEchoReply);
  677. lpsz += cbEchoReply;
  678. lpsz[0] = ':';
  679. lpsz++;
  680. memcpy(lpsz, lpszEchoHeaderIn, cbHeaderIn );
  681. lpsz += cbHeaderIn;
  682. if ( bCrlfTerminated)
  683. {
  684. lpsz[0] = '\r';
  685. lpsz[1] = '\n';
  686. lpsz += 2;
  687. }
  688. else
  689. {
  690. lpsz[0] = '\0';
  691. lpsz++;
  692. }
  693. *lpsz = '\0';
  694. }
  695. DWORD dwBufferLength;
  696. dwBufferLength = *lpdwBufferLength;
  697. error = _RequestHeaders.QueryFilteredRawHeaders(
  698. NULL,
  699. rglpFilter,
  700. sizeof(rglpFilter)/sizeof(rglpFilter[0]),
  701. TRUE,
  702. TRUE,
  703. bCrlfTerminated,
  704. lpBuffer,
  705. lpdwBufferLength
  706. );
  707. if ( !bEchoPresent )
  708. {
  709. // Nothing more to do in this case.
  710. }
  711. else if ( error == ERROR_SUCCESS )
  712. {
  713. DWORD dwBufferReqd = *lpdwBufferLength + cbHeaderOut;
  714. // Check if we have space to add extra headers.
  715. if (dwBufferReqd <= dwBufferLength)
  716. {
  717. memcpy((LPSTR)lpBuffer + *lpdwBufferLength, lpszEchoHeaderOut, cbHeaderOut);
  718. *lpdwBufferLength += cbHeaderOut - 1; // -1 to exclude terminating '\0'
  719. }
  720. else
  721. {
  722. error = ERROR_INSUFFICIENT_BUFFER;
  723. // There is a NULL termination count included both in cbHeaderOut and *lpdwBufferLength
  724. // hence the -1.
  725. *lpdwBufferLength += cbHeaderOut - 1 ;
  726. }
  727. }
  728. else if ( error == ERROR_INSUFFICIENT_BUFFER )
  729. {
  730. *lpdwBufferLength += cbHeaderOut - 1 ;
  731. }
  732. else
  733. {
  734. // For other errors just return the original error from QueryRawHeaders.
  735. }
  736. done:
  737. _ResponseHeaders.UnlockHeaders();
  738. quit:
  739. return error;
  740. }