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.

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