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.

950 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((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. for (; lpszName[queryLength] != '\0'; ++queryLength) {
  182. if ((lpszName[queryLength] == ':')
  183. || (lpszName[queryLength] == '\r')
  184. || (lpszName[queryLength] == '\n')) {
  185. break;
  186. }
  187. if (iscntrl(lpszName[queryLength])
  188. || isspace(lpszName[queryLength])) {
  189. error = ERROR_INVALID_PARAMETER;
  190. break;
  191. }
  192. }
  193. } else if ((queryModifiers & ~GlobalKnownHeaders[infoLevel].Flags) != 0) {
  194. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  195. }
  196. if (error != ERROR_SUCCESS) {
  197. goto quit;
  198. }
  199. //
  200. // if NULL buffer pointer then app wants length of option: set buffer length
  201. // to zero
  202. //
  203. if (!ARGUMENT_PRESENT(lpBuffer)) {
  204. *lpdwBufferLength = 0;
  205. }
  206. INET_ASSERT(error == ERROR_SUCCESS);
  207. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  208. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequestMapped;
  209. if (dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) {
  210. if (!IS_VALID_HTTP_STATE(pRequest, QUERY_REQUEST, TRUE)) {
  211. error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
  212. }
  213. } else {
  214. if (!IS_VALID_HTTP_STATE(pRequest, QUERY_RESPONSE, TRUE)) {
  215. error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
  216. }
  217. }
  218. if (error == ERROR_SUCCESS) {
  219. error = pRequest->QueryInfo(dwInfoLevel,
  220. lpszName,
  221. lpBuffer,
  222. lpdwBufferLength,
  223. lpdwIndex
  224. );
  225. }
  226. quit:
  227. _InternetDecNestingCount(1);
  228. done:
  229. BOOL success;
  230. if (error != ERROR_SUCCESS) {
  231. DEBUG_ERROR(HTTP, error);
  232. SetLastError(error);
  233. success = FALSE;
  234. } else {
  235. DEBUG_PRINT_API(API,
  236. INFO,
  237. ("*lpdwBufferLength = %d\n",
  238. *lpdwBufferLength
  239. ));
  240. DEBUG_DUMP_API(DUMP_API_DATA,
  241. "Query data:\n",
  242. lpBuffer,
  243. *lpdwBufferLength
  244. );
  245. success = TRUE;
  246. }
  247. if (hRequestMapped != NULL) {
  248. DereferenceObject((LPVOID)hRequestMapped);
  249. }
  250. DEBUG_LEAVE(success);
  251. return success;
  252. }
  253. INTERNETAPI
  254. BOOL
  255. WINAPI
  256. WinHttpQueryHeaders(
  257. IN HINTERNET hRequest,
  258. IN DWORD dwInfoLevel,
  259. IN LPCWSTR lpszName OPTIONAL,
  260. OUT LPVOID lpBuffer OPTIONAL,
  261. IN OUT LPDWORD lpdwBufferLength,
  262. IN OUT LPDWORD lpdwIndex OPTIONAL
  263. )
  264. /*++
  265. Routine Description:
  266. Queries information from the HTTP request handle.
  267. Arguments:
  268. hHttpRequest - An open HTTP request handle returned by HttpOpenRequest().
  269. dwInfoLevel - One of the HTTP_QUERY_* values indicating the attribute
  270. to query.
  271. lpBuffer - Pointer to the buffer to receive the information.
  272. dwBufferLength - On entry, contains the length (in BYTEs) of the data
  273. buffer. On exit, contains the size (in BYTEs) of the data written
  274. to lpBuffer.
  275. Return Value:
  276. TRUE - The query succeeded. lpBuffer contains the query information,
  277. and lpBufferLength contains the size (in BYTEs) of the information.
  278. FALSE - The operation failed. Error status is available by calling
  279. GetLastError().
  280. Comments:
  281. --*/
  282. {
  283. DEBUG_ENTER_API((DBG_API,
  284. Bool,
  285. "WinHttpQueryHeaders",
  286. "%#x, %s (%#x), %wq, %#x, %#x [%d], %#x [%d]",
  287. hRequest,
  288. InternetMapHttpOption(dwInfoLevel & HTTP_QUERY_HEADER_MASK),
  289. dwInfoLevel,
  290. lpszName? lpszName : L"<null>",
  291. lpBuffer,
  292. lpdwBufferLength,
  293. !lpdwBufferLength
  294. || IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
  295. || (lpBuffer && ProbeWriteBuffer(lpBuffer, *lpdwBufferLength))
  296. ? 0: *lpdwBufferLength,
  297. lpdwIndex,
  298. !lpdwIndex || IsBadWritePtr(lpdwIndex, sizeof(*lpdwIndex)) ? 0: *lpdwIndex
  299. ));
  300. DWORD dwErr = ERROR_SUCCESS;
  301. BOOL fResult=FALSE;
  302. MEMORYPACKET mpBuffer, mpName;
  303. if (!lpdwBufferLength
  304. || IsBadWritePtr(lpdwBufferLength, sizeof(*lpdwBufferLength))
  305. || (lpBuffer && ProbeWriteBuffer(lpBuffer, *lpdwBufferLength))
  306. || (lpdwIndex && IsBadWritePtr(lpdwIndex, sizeof(*lpdwIndex))))
  307. {
  308. dwErr = ERROR_INVALID_PARAMETER;
  309. goto cleanup;
  310. }
  311. if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
  312. {
  313. if (!lpszName
  314. || IsBadStringPtrW(lpszName, (UINT_PTR)-1))
  315. {
  316. dwErr = ERROR_INVALID_PARAMETER;
  317. goto cleanup;
  318. }
  319. ALLOC_MB(lpszName,0,mpName);
  320. if (!mpName.psStr)
  321. {
  322. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  323. goto cleanup;
  324. }
  325. UNICODE_TO_ANSI(lpszName,mpName);
  326. }
  327. if (lpBuffer)
  328. {
  329. mpBuffer.dwAlloc = mpBuffer.dwSize = *lpdwBufferLength;
  330. ALLOC_BYTES(mpBuffer.psStr, mpBuffer.dwAlloc*sizeof(CHAR));
  331. if (!mpBuffer.psStr)
  332. {
  333. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  334. goto cleanup;
  335. }
  336. }
  337. fResult = HttpQueryInfoA(hRequest,dwInfoLevel, mpName.psStr,
  338. mpBuffer.psStr, &mpBuffer.dwSize, lpdwIndex);
  339. if (!((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
  340. (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)))
  341. {
  342. // This is the default, we've been handed back a string.
  343. if (fResult)
  344. {
  345. *lpdwBufferLength = MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize + 1,
  346. NULL, 0);
  347. *lpdwBufferLength *= sizeof(WCHAR);
  348. if (*lpdwBufferLength<=mpBuffer.dwAlloc)
  349. {
  350. MultiByteToWideChar(CP_ACP, 0, mpBuffer.psStr, mpBuffer.dwSize+1,
  351. (LPWSTR)lpBuffer, mpBuffer.dwAlloc/sizeof(WCHAR));
  352. *lpdwBufferLength -= sizeof(WCHAR);
  353. }
  354. else
  355. {
  356. fResult = FALSE;
  357. dwErr = ERROR_INSUFFICIENT_BUFFER;
  358. }
  359. }
  360. else
  361. {
  362. if (GetLastError()==ERROR_INSUFFICIENT_BUFFER)
  363. {
  364. *lpdwBufferLength = mpBuffer.dwSize*sizeof(WCHAR);
  365. }
  366. }
  367. }
  368. else
  369. {
  370. if (fResult)
  371. {
  372. memcpy(lpBuffer, (LPVOID)mpBuffer.psStr, mpBuffer.dwSize);
  373. }
  374. *lpdwBufferLength = mpBuffer.dwSize;
  375. }
  376. cleanup:
  377. if (dwErr!=ERROR_SUCCESS)
  378. {
  379. SetLastError(dwErr);
  380. DEBUG_ERROR(HTTP, dwErr);
  381. }
  382. DEBUG_LEAVE_API(fResult);
  383. return fResult;
  384. }
  385. //
  386. // object methods
  387. //
  388. DWORD
  389. HTTP_REQUEST_HANDLE_OBJECT::QueryInfo(
  390. IN DWORD dwInfoLevel,
  391. IN LPCSTR headerName,
  392. OUT LPVOID lpBuffer OPTIONAL,
  393. IN OUT LPDWORD lpdwBufferLength,
  394. IN OUT LPDWORD lpdwIndex
  395. )
  396. /*++
  397. Routine Description:
  398. Header query method for HTTP_REQUEST_HANDLE_OBJECT class
  399. Arguments:
  400. dwInfoLevel - level of info (header) to get
  401. headerName - name of header with HTTP_QUERY_CUSTOM
  402. lpBuffer - pointer to user's buffer
  403. lpdwBufferLength - IN: length of user's buffer
  404. OUT: length of returned information or required buffer
  405. length if insufficient
  406. lpdwIndex - IN: 0-based index of named header to return
  407. OUT: index of next header if success returned
  408. Return Value:
  409. DWORD
  410. Success - ERROR_SUCCESS
  411. Failure - ERROR_HTTP_HEADER_NOT_FOUND
  412. Couldn't find the requested header
  413. ERROR_HTTP_INVALID_QUERY_REQUEST
  414. The caller asked for e.g. the Accept: header to be returned
  415. as a SYSTEMTIME structure, or for e.g. a request header that
  416. only exists for response headers (status code, for example)
  417. ERROR_INSUFFICIENT_BUFFER
  418. User's buffer not large enough to hold requested data
  419. --*/
  420. {
  421. INET_ASSERT(lpdwBufferLength != NULL);
  422. INET_ASSERT(lpdwIndex != NULL);
  423. DWORD error;
  424. DWORD headerNameLength;
  425. DWORD modifiers;
  426. modifiers = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
  427. dwInfoLevel &= HTTP_QUERY_HEADER_MASK;
  428. if (dwInfoLevel == HTTP_QUERY_CUSTOM) {
  429. for (headerNameLength = 0; ; ++headerNameLength) {
  430. if ((headerName[headerNameLength] == '\0')
  431. || (headerName[headerNameLength] == ':')
  432. || (headerName[headerNameLength] == '\r')
  433. || (headerName[headerNameLength] == '\n')) {
  434. break;
  435. }
  436. }
  437. } else if (dwInfoLevel == HTTP_QUERY_REQUEST_METHOD) {
  438. LPSTR lpszVerb;
  439. DWORD dwVerbLength;
  440. lpszVerb = _RequestHeaders.GetVerb(&dwVerbLength);
  441. if ((lpszVerb != NULL) && (dwVerbLength != 0)) {
  442. //
  443. // the verb is (usually) space terminated
  444. //
  445. while ((dwVerbLength > 0) && (lpszVerb[dwVerbLength - 1] == ' ')) {
  446. --dwVerbLength;
  447. }
  448. //
  449. // *lpdwBufferLength will be 0 if lpBuffer is NULL
  450. //
  451. if (*lpdwBufferLength > dwVerbLength) {
  452. memcpy(lpBuffer, lpszVerb, dwVerbLength);
  453. ((LPBYTE)lpBuffer)[dwVerbLength] = '\0';
  454. error = ERROR_SUCCESS;
  455. } else {
  456. ++dwVerbLength;
  457. error = ERROR_INSUFFICIENT_BUFFER;
  458. }
  459. *lpdwBufferLength = dwVerbLength;
  460. } else {
  461. error = ERROR_HTTP_HEADER_NOT_FOUND;
  462. }
  463. goto quit;
  464. } else {
  465. headerName = GlobalKnownHeaders[dwInfoLevel].Text;
  466. headerNameLength = GlobalKnownHeaders[dwInfoLevel].Length;
  467. }
  468. if (modifiers & HTTP_QUERY_FLAG_REQUEST_HEADERS) {
  469. //
  470. // we can always query request headers, even if the server is down
  471. // level
  472. //
  473. switch (dwInfoLevel) {
  474. case HTTP_QUERY_VERSION:
  475. case HTTP_QUERY_STATUS_CODE:
  476. case HTTP_QUERY_STATUS_TEXT:
  477. //
  478. // can't query these sub-header values from the request headers
  479. //
  480. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  481. break;
  482. case HTTP_QUERY_RAW_HEADERS:
  483. case HTTP_QUERY_RAW_HEADERS_CRLF:
  484. error = _RequestHeaders.QueryRawHeaders(
  485. NULL,
  486. dwInfoLevel == HTTP_QUERY_RAW_HEADERS_CRLF,
  487. lpBuffer,
  488. lpdwBufferLength
  489. );
  490. break;
  491. case HTTP_QUERY_ECHO_HEADERS:
  492. case HTTP_QUERY_ECHO_HEADERS_CRLF:
  493. error = QueryRequestHeadersWithEcho(
  494. dwInfoLevel == HTTP_QUERY_ECHO_HEADERS_CRLF,
  495. lpBuffer,
  496. lpdwBufferLength
  497. );
  498. break;
  499. case HTTP_QUERY_CUSTOM:
  500. if (_RequestHeaders.LockHeaders())
  501. {
  502. error = QueryRequestHeader(headerName,
  503. headerNameLength,
  504. lpBuffer,
  505. lpdwBufferLength,
  506. modifiers,
  507. lpdwIndex
  508. );
  509. _RequestHeaders.UnlockHeaders();
  510. }
  511. else
  512. {
  513. error = ERROR_NOT_ENOUGH_MEMORY;
  514. }
  515. break;
  516. default:
  517. if (_RequestHeaders.LockHeaders())
  518. {
  519. error = QueryRequestHeader( dwInfoLevel,
  520. lpBuffer,
  521. lpdwBufferLength,
  522. modifiers,
  523. lpdwIndex
  524. );
  525. _RequestHeaders.UnlockHeaders();
  526. }
  527. else
  528. {
  529. error = ERROR_NOT_ENOUGH_MEMORY;
  530. }
  531. break;
  532. }
  533. } else if (!IsDownLevel()) {
  534. switch (dwInfoLevel) {
  535. case HTTP_QUERY_VERSION:
  536. error = QueryResponseVersion(lpBuffer, lpdwBufferLength);
  537. break;
  538. case HTTP_QUERY_STATUS_CODE:
  539. error = QueryStatusCode(lpBuffer, lpdwBufferLength, modifiers);
  540. break;
  541. case HTTP_QUERY_STATUS_TEXT:
  542. error = QueryStatusText(lpBuffer, lpdwBufferLength);
  543. break;
  544. case HTTP_QUERY_RAW_HEADERS:
  545. case HTTP_QUERY_RAW_HEADERS_CRLF:
  546. error = _ResponseHeaders.QueryRawHeaders(
  547. (LPSTR)_ResponseBuffer,
  548. dwInfoLevel == HTTP_QUERY_RAW_HEADERS_CRLF,
  549. lpBuffer,
  550. lpdwBufferLength
  551. );
  552. break;
  553. case HTTP_QUERY_ECHO_HEADERS:
  554. case HTTP_QUERY_ECHO_HEADERS_CRLF:
  555. error = ERROR_HTTP_INVALID_QUERY_REQUEST;
  556. break;
  557. case HTTP_QUERY_CUSTOM:
  558. if (_RequestHeaders.LockHeaders())
  559. {
  560. error = QueryResponseHeader(
  561. headerName,
  562. headerNameLength,
  563. lpBuffer,
  564. lpdwBufferLength,
  565. modifiers,
  566. lpdwIndex
  567. );
  568. _RequestHeaders.UnlockHeaders();
  569. }
  570. else
  571. {
  572. error = ERROR_NOT_ENOUGH_MEMORY;
  573. }
  574. break;
  575. default:
  576. if (_ResponseHeaders.LockHeaders())
  577. {
  578. error = QueryResponseHeader(
  579. dwInfoLevel,
  580. lpBuffer,
  581. lpdwBufferLength,
  582. modifiers,
  583. lpdwIndex
  584. );
  585. _ResponseHeaders.UnlockHeaders();
  586. }
  587. else
  588. {
  589. error = ERROR_NOT_ENOUGH_MEMORY;
  590. }
  591. break;
  592. }
  593. } else {
  594. //
  595. // there are no response headers from down-level servers
  596. //
  597. error = ERROR_HTTP_HEADER_NOT_FOUND;
  598. }
  599. quit:
  600. return error;
  601. }
  602. DWORD
  603. HTTP_REQUEST_HANDLE_OBJECT::QueryRequestHeadersWithEcho(
  604. IN BOOL bCrlfTerminated,
  605. OUT LPVOID lpBuffer OPTIONAL,
  606. IN OUT LPDWORD lpdwBufferLength
  607. )
  608. /*++
  609. Routine Description:
  610. Header query for request headers with echo headers added if any..
  611. Arguments:
  612. bCrlfTerminated - should the headers be seperated by CRLF's
  613. lpBuffer - pointer to user's buffer
  614. lpdwBufferLength - IN: length of user's buffer
  615. OUT: length of returned information or required buffer
  616. length if insufficient
  617. Return Value:
  618. DWORD
  619. Success - ERROR_SUCCESS
  620. Failure -
  621. ERROR_INSUFFICIENT_BUFFER
  622. User's buffer not large enough to hold requested data
  623. --*/
  624. {
  625. INET_ASSERT(lpdwBufferLength != NULL);
  626. DWORD error;
  627. LPSTR lpszEchoHeaderIn = NULL ;
  628. LPSTR lpszEchoHeaderOut = NULL;
  629. DWORD cbHeaderIn = 0;
  630. DWORD cbHeaderOut = 0;
  631. BOOL bEchoPresent = FALSE;
  632. // List of headers to filter out of the Request headers
  633. LPSTR rglpFilter [ ] =
  634. {
  635. GlobalKnownHeaders[HTTP_QUERY_AUTHORIZATION].Text,
  636. GlobalKnownHeaders[HTTP_QUERY_CONNECTION].Text,
  637. GlobalKnownHeaders[HTTP_QUERY_CONTENT_LENGTH].Text,
  638. GlobalKnownHeaders[HTTP_QUERY_COOKIE].Text,
  639. GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Text,
  640. GlobalKnownHeaders[HTTP_QUERY_HOST].Text,
  641. GlobalKnownHeaders[HTTP_QUERY_IF_MODIFIED_SINCE].Text,
  642. GlobalKnownHeaders[HTTP_QUERY_IF_MATCH].Text,
  643. GlobalKnownHeaders[HTTP_QUERY_IF_NONE_MATCH].Text,
  644. GlobalKnownHeaders[HTTP_QUERY_IF_RANGE].Text,
  645. GlobalKnownHeaders[HTTP_QUERY_IF_UNMODIFIED_SINCE].Text,
  646. GlobalKnownHeaders[HTTP_QUERY_PROXY_AUTHORIZATION].Text,
  647. GlobalKnownHeaders[HTTP_QUERY_PROXY_CONNECTION].Text,
  648. GlobalKnownHeaders[HTTP_QUERY_RANGE].Text,
  649. GlobalKnownHeaders[HTTP_QUERY_UNLESS_MODIFIED_SINCE].Text,
  650. };
  651. if (!_ResponseHeaders.LockHeaders())
  652. {
  653. error = ERROR_NOT_ENOUGH_MEMORY;
  654. goto quit;
  655. }
  656. error = FastQueryResponseHeader(HTTP_QUERY_ECHO_REQUEST,
  657. (LPVOID *)&lpszEchoHeaderIn,
  658. &cbHeaderIn,
  659. 0);
  660. if (error == ERROR_SUCCESS)
  661. {
  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. __try
  670. {
  671. lpszEchoHeaderOut = (LPSTR) _alloca(cbHeaderOut); // Add 1 for null terminator.
  672. }
  673. __except (GetExceptionCode() == STATUS_STACK_OVERFLOW ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  674. {
  675. lpszEchoHeaderOut = NULL;
  676. }
  677. if ( lpszEchoHeaderOut == NULL)
  678. {
  679. error = ERROR_NOT_ENOUGH_MEMORY;
  680. goto done;
  681. }
  682. LPSTR lpsz = lpszEchoHeaderOut;
  683. memcpy(lpszEchoHeaderOut, GlobalKnownHeaders[HTTP_QUERY_ECHO_REPLY].Text, cbEchoReply);
  684. lpsz += cbEchoReply;
  685. lpsz[0] = ':';
  686. lpsz++;
  687. memcpy(lpsz, lpszEchoHeaderIn, cbHeaderIn );
  688. lpsz += cbHeaderIn;
  689. if ( bCrlfTerminated)
  690. {
  691. lpsz[0] = '\r';
  692. lpsz[1] = '\n';
  693. lpsz += 2;
  694. }
  695. else
  696. {
  697. lpsz[0] = '\0';
  698. lpsz++;
  699. }
  700. *lpsz = '\0';
  701. }
  702. DWORD dwBufferLength;
  703. dwBufferLength = *lpdwBufferLength;
  704. error = _RequestHeaders.QueryFilteredRawHeaders(
  705. NULL,
  706. rglpFilter,
  707. sizeof(rglpFilter)/sizeof(rglpFilter[0]),
  708. TRUE,
  709. TRUE,
  710. bCrlfTerminated,
  711. lpBuffer,
  712. lpdwBufferLength
  713. );
  714. if ( !bEchoPresent )
  715. {
  716. // Nothing more to do in this case.
  717. }
  718. else if ( error == ERROR_SUCCESS )
  719. {
  720. DWORD dwBufferReqd = *lpdwBufferLength + cbHeaderOut;
  721. // Check if we have space to add extra headers.
  722. if (dwBufferReqd <= dwBufferLength)
  723. {
  724. memcpy((LPSTR)lpBuffer + *lpdwBufferLength, lpszEchoHeaderOut, cbHeaderOut);
  725. *lpdwBufferLength += cbHeaderOut - 1; // -1 to exclude terminating '\0'
  726. }
  727. else
  728. {
  729. error = ERROR_INSUFFICIENT_BUFFER;
  730. // There is a NULL termination count included both in cbHeaderOut and *lpdwBufferLength
  731. // hence the -1.
  732. *lpdwBufferLength += cbHeaderOut - 1 ;
  733. }
  734. }
  735. else if ( error == ERROR_INSUFFICIENT_BUFFER )
  736. {
  737. *lpdwBufferLength += cbHeaderOut - 1 ;
  738. }
  739. else
  740. {
  741. // For other errors just return the original error from QueryRawHeaders.
  742. }
  743. done:
  744. _ResponseHeaders.UnlockHeaders();
  745. quit:
  746. return error;
  747. }