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.

685 lines
18 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. add.cxx
  5. Abstract:
  6. This file contains the implementation of the HttpAddRequestHeadersA API.
  7. The following functions are exported by this module:
  8. HttpAddRequestHeadersA
  9. WinHttpAddRequestHeaders
  10. Author:
  11. Keith Moore (keithmo) 16-Nov-1994
  12. Revision History:
  13. Modified to make HttpAddRequestHeadersA remotable. madana (2/8/95)
  14. --*/
  15. #include <wininetp.h>
  16. #include "httpp.h"
  17. //
  18. // private manifests
  19. //
  20. #define VALID_ADD_FLAGS (HTTP_ADDREQ_FLAG_ADD_IF_NEW \
  21. | HTTP_ADDREQ_FLAG_ADD \
  22. | HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA \
  23. | HTTP_ADDREQ_FLAG_REPLACE \
  24. | HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON \
  25. )
  26. //
  27. // functions
  28. //
  29. INTERNETAPI
  30. BOOL
  31. WINAPI
  32. HttpAddRequestHeadersA(
  33. IN HINTERNET hRequest,
  34. IN LPCSTR lpszHeaders,
  35. IN DWORD dwHeadersLength,
  36. IN DWORD dwModifiers
  37. )
  38. /*++
  39. Routine Description:
  40. Appends additional header(s) to an HTTP request handle
  41. Arguments:
  42. hRequest - An open HTTP request handle returned by HttpOpenRequest()
  43. lpszHeaders - The headers to append to the request. Each header must be
  44. terminated by a CR/LF pair.
  45. dwHeadersLength - The length (in characters) of the headers. If this is -1L
  46. then lpszHeaders is assumed to be zero terminated (ASCIIZ)
  47. dwModifiers - flags controlling operation. Can be one or more of:
  48. HTTP_ADDREQ_FLAG_ADD_IF_NEW
  49. - add the header, but only if it does not already
  50. exist. Index must be zero
  51. HTTP_ADDREQ_FLAG_ADD
  52. - if HTTP_ADDREQ_FLAG_REPLACE is set, but the header
  53. is not found and this flag is set then the header
  54. is added, so long as there is a valid header-value
  55. HTTP_ADDREQ_FLAG_COALESCE
  56. HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON
  57. HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA
  58. - concatenate headers of same name. E.g. if we
  59. already have "Accept: text/html" then adding
  60. "Accept: text/*" will create
  61. "Accept: text/html, text/*"
  62. HTTP_ADDREQ_FLAG_REPLACE
  63. - replaces the named header. Only one header can be
  64. supplied. If header-value is empty then the header
  65. is removed
  66. Return Value:
  67. Success - TRUE
  68. The header was appended successfully
  69. Failure - FALSE
  70. The operation failed. Error status is available by calling
  71. GetLastError()
  72. --*/
  73. {
  74. DEBUG_ENTER((DBG_API,
  75. Bool,
  76. "HttpAddRequestHeadersA",
  77. "%#x, %.80q, %d, %#x",
  78. hRequest,
  79. lpszHeaders,
  80. dwHeadersLength,
  81. dwModifiers
  82. ));
  83. DWORD error;
  84. HINTERNET hRequestMapped = NULL;
  85. DWORD nestingLevel = 0;
  86. if (!GlobalDataInitialized) {
  87. error = ERROR_WINHTTP_NOT_INITIALIZED;
  88. goto done;
  89. }
  90. //
  91. // get the thread info
  92. //
  93. LPINTERNET_THREAD_INFO lpThreadInfo;
  94. lpThreadInfo = InternetGetThreadInfo();
  95. if (lpThreadInfo == NULL) {
  96. error = ERROR_WINHTTP_INTERNAL_ERROR;
  97. goto done;
  98. }
  99. //
  100. // map the handle
  101. //
  102. error = MapHandleToAddress(hRequest, (LPVOID *)&hRequestMapped, FALSE);
  103. if (error != ERROR_SUCCESS) {
  104. goto quit;
  105. }
  106. _InternetIncNestingCount();
  107. nestingLevel = 1;
  108. //
  109. // validate handle
  110. //
  111. BOOL isLocal;
  112. BOOL isAsync;
  113. error = RIsHandleLocal(hRequestMapped,
  114. &isLocal,
  115. &isAsync,
  116. TypeHttpRequestHandle
  117. );
  118. if (error != ERROR_SUCCESS) {
  119. goto quit;
  120. }
  121. //
  122. // validate parameters
  123. //
  124. INET_ASSERT(!(
  125. (lpszHeaders == NULL)
  126. || (*lpszHeaders == '\0')
  127. || (dwHeadersLength == 0)
  128. || (dwModifiers & (HTTP_ADDREQ_FLAGS_MASK & ~VALID_ADD_FLAGS))) );
  129. INET_ASSERT(error == ERROR_SUCCESS);
  130. //
  131. // BUGBUG - we should determine whether the app is trying to give us a bogus
  132. // header, and whether the header conforms to the format:
  133. //
  134. // "<header>[:[ <value>]]"
  135. //
  136. if (dwHeadersLength == (DWORD)-1)
  137. {
  138. dwHeadersLength = (DWORD)lstrlen(lpszHeaders);
  139. }
  140. if (error == ERROR_SUCCESS) {
  141. error = wHttpAddRequestHeaders(hRequestMapped,
  142. lpszHeaders,
  143. dwHeadersLength,
  144. dwModifiers
  145. );
  146. }
  147. quit:
  148. _InternetDecNestingCount(nestingLevel);
  149. done:
  150. if (error != ERROR_SUCCESS) {
  151. DEBUG_ERROR(HTTP, error);
  152. SetLastError(error);
  153. }
  154. if (hRequestMapped != NULL) {
  155. DereferenceObject((LPVOID)hRequestMapped);
  156. }
  157. DEBUG_LEAVE(error == ERROR_SUCCESS);
  158. return error == ERROR_SUCCESS;
  159. }
  160. INTERNETAPI
  161. BOOL
  162. WINAPI
  163. WinHttpAddRequestHeaders(
  164. IN HINTERNET hRequest,
  165. IN LPCWSTR lpszHeaders,
  166. IN DWORD dwHeadersLength,
  167. IN DWORD dwModifiers
  168. )
  169. /*++
  170. Routine Description:
  171. Appends additional header(s) to an HTTP request handle.
  172. Arguments:
  173. hHttpRequest - An open HTTP request handle returned by HttpOpenRequest().
  174. lpszHeaders - The headers to append to the request. Each header must be
  175. terminated by a CR/LF pair.
  176. dwHeadersLength - The length (in characters) of the headers. If this is
  177. -1L, then lpszHeaders is assumed to be zero terminated (ASCIIZ).
  178. dwModifiers -
  179. Return Value:
  180. TRUE - The header was appended successfully.
  181. FALSE - The operation failed. Error status is available by calling
  182. GetLastError().
  183. Comments:
  184. --*/
  185. {
  186. DEBUG_ENTER_API((DBG_API,
  187. Bool,
  188. "WinHttpAddRequestHeaders",
  189. "%#x, %.80wq, %d, %#x",
  190. hRequest,
  191. lpszHeaders,
  192. dwHeadersLength,
  193. dwModifiers
  194. ));
  195. DWORD dwErr = ERROR_SUCCESS;
  196. BOOL fResult = FALSE;
  197. if (!lpszHeaders
  198. || *lpszHeaders==L'\0'
  199. || !dwHeadersLength
  200. || ((dwHeadersLength == -1)
  201. ? IsBadStringPtrW(lpszHeaders, (UINT_PTR)-1)
  202. : IsBadReadPtr(lpszHeaders, dwHeadersLength))
  203. || (dwModifiers & (HTTP_ADDREQ_FLAGS_MASK & ~VALID_ADD_FLAGS)))
  204. {
  205. dwErr = ERROR_INVALID_PARAMETER;
  206. }
  207. else
  208. {
  209. MEMORYPACKET mpHeaders;
  210. ALLOC_MB(lpszHeaders, (dwHeadersLength==-1L ? 0 : dwHeadersLength), mpHeaders);
  211. if (mpHeaders.psStr)
  212. {
  213. UNICODE_TO_ANSI(lpszHeaders, mpHeaders);
  214. fResult = HttpAddRequestHeadersA(hRequest, mpHeaders.psStr, mpHeaders.dwSize, dwModifiers);
  215. }
  216. else
  217. {
  218. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  219. }
  220. }
  221. if (dwErr!=ERROR_SUCCESS)
  222. {
  223. SetLastError(dwErr);
  224. DEBUG_ERROR(HTTP, dwErr);
  225. }
  226. DEBUG_LEAVE_API(fResult);
  227. return fResult;
  228. }
  229. #define DEFAULT_BEGIN_SIZE 8
  230. #define EXPAND_SIZE 8
  231. static const CHAR IsValidHeaderNameChar[] =
  232. {
  233. // 0 1 2 3 4 5 6 7
  234. FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  235. FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  236. FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  237. FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  238. // ' ' '"'
  239. FALSE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE,
  240. // '(' ')' ',' '/'
  241. FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE,
  242. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  243. // ':' ';' '<' '=' '>' '?'
  244. TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
  245. // '@'
  246. FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  247. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  248. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  249. // '[' '\' ']'
  250. TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE,
  251. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  252. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  253. TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
  254. // '{'' '}' DEL
  255. TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE
  256. };
  257. BOOL IsValidHeaderName(LPCWSTR lpszHeaderName)
  258. {
  259. WCHAR wch;
  260. int nIndex=0;
  261. for ( ; (wch=lpszHeaderName[nIndex]) != 0; nIndex++)
  262. {
  263. if ((wch > ARRAY_ELEMENTS(IsValidHeaderNameChar))
  264. || !IsValidHeaderNameChar[wch])
  265. {
  266. return FALSE;
  267. }
  268. }
  269. return TRUE;
  270. }
  271. typedef struct _headerrec
  272. {
  273. LPSTR lpName;
  274. int nName;
  275. LPSTR lpValue;
  276. int nValue;
  277. }
  278. HEADER_REC;
  279. PUBLIC
  280. DWORD
  281. wHttpAddRequestHeaders(
  282. IN HINTERNET hRequest,
  283. IN LPCSTR lpszHeaders,
  284. IN DWORD dwHeadersLength,
  285. IN DWORD dwModifiers
  286. )
  287. /*++
  288. Routine Description:
  289. Worker function to append additional header(s) to an HTTP request handle
  290. Arguents:
  291. hRequest - handle of HTTP request
  292. lpszHeaders - pointer to buffer containing one or more headers
  293. dwHeadersLength - length of lpszHeaders. Cannot be -1 at this stage
  294. dwModifiers - flags controlling operation
  295. Return Value:
  296. DWORD
  297. Success - ERROR_SUCCESS
  298. Failure - ERROR_INVALID_PARAMETER
  299. The header string(s) was bad after all
  300. ERROR_WINHTTP_INCORRECT_HANDLE_STATE
  301. We can't add headers to this object at this time
  302. ERROR_HTTP_HEADER_NOT_FOUND
  303. We were asked to replace a header, but couldn't find it
  304. ERROR_HTTP_HEADER_ALREADY_EXISTS
  305. We were asked to add a header, only if one of the same name
  306. doesn't already exist. It does
  307. --*/
  308. {
  309. //
  310. // dwHeadersLength cannot be -1 or 0 at this stage. Nor can lpszHeaders be
  311. // NULL
  312. //
  313. INET_ASSERT(lpszHeaders != NULL);
  314. INET_ASSERT(dwHeadersLength != (DWORD)-1);
  315. INET_ASSERT(dwHeadersLength != 0);
  316. DEBUG_ENTER((DBG_HTTP,
  317. Dword,
  318. "wHttpAddRequestHeaders",
  319. "%#x, %#x [%.80q], %d, %#x",
  320. hRequest,
  321. lpszHeaders,
  322. lpszHeaders,
  323. dwHeadersLength,
  324. dwModifiers
  325. ));
  326. //
  327. // get the underlying object and check that we can add headers
  328. //
  329. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  330. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequest;
  331. HEADER_REC* pHeaders = NULL;
  332. DWORD error;
  333. if (!IS_VALID_HTTP_STATE(pRequest, ADD, TRUE))
  334. {
  335. error = ERROR_WINHTTP_INCORRECT_HANDLE_STATE;
  336. goto quit;
  337. }
  338. DWORD offset;
  339. LPSTR header;
  340. offset = 0;
  341. header = (LPSTR)lpszHeaders;
  342. int nCount = DEFAULT_BEGIN_SIZE;
  343. pHeaders = (HEADER_REC *)ALLOCATE_FIXED_MEMORY (sizeof(HEADER_REC)*nCount);
  344. int nHeader = 0;
  345. if (!pHeaders)
  346. {
  347. error = ERROR_NOT_ENOUGH_MEMORY;
  348. goto quit;
  349. }
  350. error = ERROR_SUCCESS;
  351. do
  352. {
  353. //
  354. // first time: ignore any empty strings; subsequent time: clean off any
  355. // trailing line termination
  356. //
  357. while ((offset < dwHeadersLength)
  358. && ((lpszHeaders[offset] == '\r') || (lpszHeaders[offset] == '\n')))
  359. {
  360. ++offset;
  361. }
  362. if (offset == dwHeadersLength)
  363. {
  364. //
  365. // even if app tried adding empty line(s), we return success
  366. //
  367. error = ERROR_SUCCESS;
  368. break;
  369. }
  370. DWORD length;
  371. DWORD nameLength;
  372. DWORD valueLength;
  373. LPSTR value;
  374. nameLength = 0;
  375. valueLength = 0;
  376. value = NULL;
  377. //
  378. // break the header into header-name, header-value pairs. Exclude CR-LF
  379. // from the header-value (if present)
  380. //
  381. for (length = 0, header = (LPSTR)&lpszHeaders[offset];
  382. offset < dwHeadersLength;
  383. ++length, ++offset)
  384. {
  385. char ch = header[length];
  386. if (ch == '\r')
  387. {
  388. //
  389. // end of this particular header?
  390. //
  391. if (((offset+2) < dwHeadersLength)
  392. && nameLength
  393. && (header[length+1] == '\n')
  394. && ((header[length+2] == ' ')
  395. || (header[length+2] == '\t'))
  396. )
  397. {
  398. //LWS allowing header to spill over to next line
  399. length+=2;
  400. offset+=2;
  401. }
  402. else
  403. {
  404. break;
  405. }
  406. }
  407. else if (ch == '\n')
  408. {
  409. //
  410. // end of this particular header?
  411. //
  412. break;
  413. }
  414. else if (ch == ':')
  415. {
  416. if (nameLength == 0)
  417. {
  418. //
  419. // found end of header name
  420. //
  421. nameLength = length;
  422. value = &header[length];
  423. }
  424. }
  425. if (nameLength == 0)
  426. {
  427. if ((ch > ARRAY_ELEMENTS(IsValidHeaderNameChar))
  428. || !IsValidHeaderNameChar[ch])
  429. {
  430. error = ERROR_INVALID_PARAMETER;
  431. goto quit;
  432. }
  433. }
  434. }
  435. if (length == 0)
  436. {
  437. //
  438. // empty string
  439. //
  440. continue;
  441. }
  442. else if (nameLength == 0)
  443. {
  444. //
  445. // entry consists of just header-name (e.g. "Accept[\r\n]")
  446. //
  447. nameLength = length;
  448. }
  449. else
  450. {
  451. //
  452. // find the start of the header-value
  453. //
  454. valueLength = (DWORD) (header + length - value);
  455. //ideally we wouldn't eat through all the leading white space or : in the
  456. // header value because they may be significant.
  457. // Don't know of any examples though, so can keep it as such.
  458. //
  459. // N.B. We are allowing any mixture of ':' and ' ' between header
  460. // name and value, but this is probably not a big deal...
  461. //
  462. while ((*value == ':') || (*value == ' ') && (valueLength != 0))
  463. {
  464. ++value;
  465. --valueLength;
  466. }
  467. }
  468. if (!value
  469. && !(dwModifiers & (HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD_IF_NEW)))
  470. {
  471. error = ERROR_INVALID_PARAMETER;
  472. goto quit;
  473. }
  474. pHeaders[nHeader].lpName = header;
  475. pHeaders[nHeader].nName = nameLength;
  476. pHeaders[nHeader].lpValue = value;
  477. pHeaders[nHeader].nValue = valueLength;
  478. if (++nHeader >= nCount)
  479. {
  480. nCount += EXPAND_SIZE;
  481. HEADER_REC* pNewHeaders = (HEADER_REC *)REALLOCATE_MEMORY(pHeaders, sizeof(HEADER_REC)*nCount);
  482. if (pNewHeaders)
  483. pHeaders = pNewHeaders;
  484. else
  485. {
  486. FREE_MEMORY(pHeaders);
  487. pHeaders = NULL;
  488. error = ERROR_NOT_ENOUGH_MEMORY;
  489. goto quit;
  490. }
  491. }
  492. }
  493. while (error == ERROR_SUCCESS);
  494. for (int nIndex=0; nIndex<nHeader; nIndex++)
  495. {
  496. if (dwModifiers
  497. & (HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD_IF_NEW))
  498. {
  499. //
  500. // replace or remove the header
  501. //
  502. error = pRequest->ReplaceRequestHeader(
  503. pHeaders[nIndex].lpName,
  504. pHeaders[nIndex].nName,
  505. pHeaders[nIndex].lpValue,
  506. pHeaders[nIndex].nValue,
  507. dwModifiers & HTTP_ADDREQ_INDEX_MASK,
  508. dwModifiers & HTTP_ADDREQ_FLAGS_MASK
  509. );
  510. }
  511. else
  512. {
  513. //
  514. // add a single, unterminated header string to the request headers.
  515. // Since these headers came from the app, we don't trust it to get
  516. // the header termination right (number & type of line terminators)
  517. // so we add it ourselves
  518. //
  519. error = pRequest->AddRequestHeader(
  520. pHeaders[nIndex].lpName,
  521. pHeaders[nIndex].nName,
  522. pHeaders[nIndex].lpValue,
  523. pHeaders[nIndex].nValue,
  524. dwModifiers & HTTP_ADDREQ_INDEX_MASK,
  525. dwModifiers & HTTP_ADDREQ_FLAGS_MASK
  526. );
  527. }
  528. if (error != ERROR_SUCCESS)
  529. break;
  530. }
  531. quit:
  532. if (pHeaders)
  533. {
  534. FREE_MEMORY(pHeaders);
  535. }
  536. DEBUG_LEAVE(error);
  537. return error;
  538. }