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.

553 lines
15 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. HttpAddRequestHeadersW
  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_(BOOL) HttpAddRequestHeadersA(
  30. IN HINTERNET hRequest,
  31. IN LPCSTR lpszHeaders,
  32. IN DWORD dwHeadersLength,
  33. IN DWORD dwModifiers
  34. )
  35. /*++
  36. Routine Description:
  37. Appends additional header(s) to an HTTP request handle
  38. Arguments:
  39. hRequest - An open HTTP request handle returned by HttpOpenRequest()
  40. lpszHeaders - The headers to append to the request. Each header must be
  41. terminated by a CR/LF pair.
  42. dwHeadersLength - The length (in characters) of the headers. If this is -1L
  43. then lpszHeaders is assumed to be zero terminated (ASCIIZ)
  44. dwModifiers - flags controlling operation. Can be one or more of:
  45. HTTP_ADDREQ_FLAG_ADD_IF_NEW
  46. - add the header, but only if it does not already
  47. exist. Index must be zero
  48. HTTP_ADDREQ_FLAG_ADD
  49. - if HTTP_ADDREQ_FLAG_REPLACE is set, but the header
  50. is not found and this flag is set then the header
  51. is added, so long as there is a valid header-value
  52. HTTP_ADDREQ_FLAG_COALESCE
  53. HTTP_ADDREQ_FLAG_COALESCE_WITH_SEMICOLON
  54. HTTP_ADDREQ_FLAG_COALESCE_WITH_COMMA
  55. - concatenate headers of same name. E.g. if we
  56. already have "Accept: text/html" then adding
  57. "Accept: text/*" will create
  58. "Accept: text/html, text/*"
  59. HTTP_ADDREQ_FLAG_REPLACE
  60. - replaces the named header. Only one header can be
  61. supplied. If header-value is empty then the header
  62. is removed
  63. Return Value:
  64. Success - TRUE
  65. The header was appended successfully
  66. Failure - FALSE
  67. The operation failed. Error status is available by calling
  68. GetLastError()
  69. --*/
  70. {
  71. DEBUG_ENTER_API((DBG_API,
  72. Bool,
  73. "HttpAddRequestHeadersA",
  74. "%#x, %.80q, %d, %#x",
  75. hRequest,
  76. lpszHeaders,
  77. dwHeadersLength,
  78. dwModifiers
  79. ));
  80. DWORD error;
  81. HINTERNET hRequestMapped = NULL;
  82. DWORD nestingLevel = 0;
  83. if (!GlobalDataInitialized) {
  84. error = ERROR_INTERNET_NOT_INITIALIZED;
  85. goto done;
  86. }
  87. //
  88. // get the thread info
  89. //
  90. LPINTERNET_THREAD_INFO lpThreadInfo;
  91. lpThreadInfo = InternetGetThreadInfo();
  92. if (lpThreadInfo == NULL) {
  93. error = ERROR_INTERNET_INTERNAL_ERROR;
  94. goto done;
  95. }
  96. //
  97. // map the handle
  98. //
  99. error = MapHandleToAddress(hRequest, (LPVOID *)&hRequestMapped, FALSE);
  100. if (error != ERROR_SUCCESS) {
  101. goto quit;
  102. }
  103. _InternetIncNestingCount();
  104. nestingLevel = 1;
  105. //
  106. // validate handle
  107. //
  108. BOOL isLocal;
  109. BOOL isAsync;
  110. error = RIsHandleLocal(hRequestMapped,
  111. &isLocal,
  112. &isAsync,
  113. TypeHttpRequestHandle
  114. );
  115. if (error != ERROR_SUCCESS) {
  116. goto quit;
  117. }
  118. //
  119. // validate parameters
  120. //
  121. if ((lpszHeaders == NULL)
  122. || (*lpszHeaders == '\0')
  123. || (dwHeadersLength == 0)
  124. || (dwModifiers & (HTTP_ADDREQ_FLAGS_MASK & ~VALID_ADD_FLAGS))) {
  125. error = ERROR_INVALID_PARAMETER;
  126. goto quit;
  127. }
  128. INET_ASSERT(error == ERROR_SUCCESS);
  129. //
  130. // BUGBUG - we should determine whether the app is trying to give us a bogus
  131. // header, and whether the header conforms to the format:
  132. //
  133. // "<header>[:[ <value>]]"
  134. //
  135. __try {
  136. if (dwHeadersLength == (DWORD)-1) {
  137. dwHeadersLength = (DWORD)lstrlen(lpszHeaders);
  138. } else {
  139. //
  140. // perform our own IsBadStringPtr() - don't have to call another
  141. // function or register extra exception handlers
  142. //
  143. for (DWORD i = 0; i < dwHeadersLength; ++i) {
  144. char ch = *((char volatile *)&lpszHeaders[i]);
  145. }
  146. }
  147. } __except(EXCEPTION_EXECUTE_HANDLER) {
  148. error = ERROR_INVALID_PARAMETER;
  149. goto quit;
  150. }
  151. ENDEXCEPT
  152. if (error == ERROR_SUCCESS) {
  153. error = wHttpAddRequestHeaders(hRequestMapped,
  154. lpszHeaders,
  155. dwHeadersLength,
  156. dwModifiers
  157. );
  158. }
  159. quit:
  160. _InternetDecNestingCount(nestingLevel);
  161. done:
  162. if (error != ERROR_SUCCESS) {
  163. DEBUG_ERROR(HTTP, error);
  164. SetLastError(error);
  165. }
  166. if (hRequestMapped != NULL) {
  167. DereferenceObject((LPVOID)hRequestMapped);
  168. }
  169. DEBUG_LEAVE_API(error == ERROR_SUCCESS);
  170. return error == ERROR_SUCCESS;
  171. }
  172. INTERNETAPI_(BOOL) HttpAddRequestHeadersW(
  173. IN HINTERNET hRequest,
  174. IN LPCWSTR lpszHeaders,
  175. IN DWORD dwHeadersLength,
  176. IN DWORD dwModifiers
  177. )
  178. /*++
  179. Routine Description:
  180. Appends additional header(s) to an HTTP request handle.
  181. Arguments:
  182. hHttpRequest - An open HTTP request handle returned by HttpOpenRequest().
  183. lpszHeaders - The headers to append to the request. Each header must be
  184. terminated by a CR/LF pair.
  185. dwHeadersLength - The length (in characters) of the headers. If this is
  186. -1L, then lpszHeaders is assumed to be zero terminated (ASCIIZ).
  187. dwModifiers -
  188. Return Value:
  189. TRUE - The header was appended successfully.
  190. FALSE - The operation failed. Error status is available by calling
  191. GetLastError().
  192. Comments:
  193. --*/
  194. {
  195. DEBUG_ENTER_API((DBG_API,
  196. Bool,
  197. "HttpAddRequestHeadersW",
  198. "%#x, %.80wq, %d, %#x",
  199. hRequest,
  200. lpszHeaders,
  201. dwHeadersLength,
  202. dwModifiers
  203. ));
  204. DWORD dwErr = ERROR_SUCCESS;
  205. BOOL fResult = FALSE;
  206. if (!lpszHeaders || *lpszHeaders==L'\0' || !dwHeadersLength
  207. || IsBadStringPtrW(lpszHeaders, dwHeadersLength))
  208. {
  209. dwErr = ERROR_INVALID_PARAMETER;
  210. }
  211. else
  212. {
  213. MEMORYPACKET mpHeaders;
  214. ALLOC_MB(lpszHeaders, (dwHeadersLength==-1L ? 0 : dwHeadersLength), mpHeaders);
  215. if (mpHeaders.psStr)
  216. {
  217. UNICODE_TO_ANSI(lpszHeaders, mpHeaders);
  218. fResult = HttpAddRequestHeadersA(hRequest, mpHeaders.psStr, mpHeaders.dwSize, dwModifiers);
  219. }
  220. else
  221. {
  222. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  223. }
  224. }
  225. if (dwErr!=ERROR_SUCCESS)
  226. {
  227. SetLastError(dwErr);
  228. DEBUG_ERROR(HTTP, dwErr);
  229. }
  230. DEBUG_LEAVE_API(fResult);
  231. return fResult;
  232. }
  233. PUBLIC
  234. DWORD
  235. wHttpAddRequestHeaders(
  236. IN HINTERNET hRequest,
  237. IN LPCSTR lpszHeaders,
  238. IN DWORD dwHeadersLength,
  239. IN DWORD dwModifiers
  240. )
  241. /*++
  242. Routine Description:
  243. Worker function to append additional header(s) to an HTTP request handle
  244. Arguents:
  245. hRequest - handle of HTTP request
  246. lpszHeaders - pointer to buffer containing one or more headers
  247. dwHeadersLength - length of lpszHeaders. Cannot be -1 at this stage
  248. dwModifiers - flags controlling operation
  249. Return Value:
  250. DWORD
  251. Success - ERROR_SUCCESS
  252. Failure - ERROR_INVALID_PARAMETER
  253. The header string(s) was bad after all
  254. ERROR_INTERNET_INCORRECT_HANDLE_STATE
  255. We can't add headers to this object at this time
  256. ERROR_HTTP_HEADER_NOT_FOUND
  257. We were asked to replace a header, but couldn't find it
  258. ERROR_HTTP_HEADER_ALREADY_EXISTS
  259. We were asked to add a header, only if one of the same name
  260. doesn't already exist. It does
  261. --*/
  262. {
  263. //
  264. // dwHeadersLength cannot be -1 or 0 at this stage. Nor can lpszHeaders be
  265. // NULL
  266. //
  267. INET_ASSERT(lpszHeaders != NULL);
  268. INET_ASSERT(dwHeadersLength != (DWORD)-1);
  269. INET_ASSERT(dwHeadersLength != 0);
  270. DEBUG_ENTER((DBG_HTTP,
  271. Dword,
  272. "wHttpAddRequestHeaders",
  273. "%#x, %#x [%.80q], %d, %#x",
  274. hRequest,
  275. lpszHeaders,
  276. lpszHeaders,
  277. dwHeadersLength,
  278. dwModifiers
  279. ));
  280. //
  281. // get the underlying object and check that we can add headers
  282. //
  283. HTTP_REQUEST_HANDLE_OBJECT * pRequest;
  284. pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequest;
  285. DWORD error;
  286. if (!IS_VALID_HTTP_STATE(pRequest, ADD, TRUE)) {
  287. error = ERROR_INTERNET_INCORRECT_HANDLE_STATE;
  288. goto quit;
  289. }
  290. DWORD offset;
  291. LPSTR header;
  292. offset = 0;
  293. header = (LPSTR)lpszHeaders;
  294. do {
  295. //
  296. // first time: ignore any empty strings; subsequent time: clean off any
  297. // trailing line termination
  298. //
  299. while ((offset < dwHeadersLength)
  300. && ((lpszHeaders[offset] == '\r') || (lpszHeaders[offset] == '\n'))) {
  301. ++offset;
  302. }
  303. if (offset == dwHeadersLength) {
  304. //
  305. // even if app tried adding empty line(s), we return success
  306. //
  307. error = ERROR_SUCCESS;
  308. break;
  309. }
  310. DWORD length;
  311. DWORD nameLength;
  312. DWORD valueLength;
  313. LPSTR value;
  314. BOOL done;
  315. nameLength = 0;
  316. valueLength = 0;
  317. value = NULL;
  318. //
  319. // break the header into header-name, header-value pairs. Exclude CR-LF
  320. // from the header-value (if present)
  321. //
  322. for (length = 0, header = (LPSTR)&lpszHeaders[offset];
  323. offset < dwHeadersLength;
  324. ++length, ++offset) {
  325. char ch = header[length];
  326. if ((ch == '\r') || (ch == '\n')) {
  327. //
  328. // end of this particular header
  329. //
  330. break;
  331. } else if (ch == ':') {
  332. if (nameLength == 0) {
  333. //
  334. // found end of header name
  335. //
  336. nameLength = length;
  337. value = &header[length];
  338. }
  339. }
  340. }
  341. if (length == 0) {
  342. //
  343. // empty string
  344. //
  345. continue;
  346. } else if (nameLength == 0) {
  347. //
  348. // entry consists of just header-name (e.g. "Accept[\r\n]")
  349. //
  350. nameLength = length;
  351. } else {
  352. //
  353. // find the start of the header-value
  354. //
  355. valueLength = (DWORD) (header + length - value);
  356. //
  357. // N.B. We are allowing any mixture of ':' and ' ' between header
  358. // name and value, but this is probably not a big deal...
  359. //
  360. while ((*value == ':') || (*value == ' ') && (valueLength != 0)) {
  361. ++value;
  362. --valueLength;
  363. }
  364. }
  365. if (dwModifiers
  366. & (HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD_IF_NEW)) {
  367. //
  368. // replace or remove the header
  369. //
  370. error = pRequest->ReplaceRequestHeader(
  371. header,
  372. nameLength,
  373. value,
  374. valueLength,
  375. dwModifiers & HTTP_ADDREQ_INDEX_MASK,
  376. dwModifiers & HTTP_ADDREQ_FLAGS_MASK
  377. );
  378. } else if (valueLength != 0) {
  379. //
  380. // add a single, unterminated header string to the request headers.
  381. // Since these headers came from the app, we don't trust it to get
  382. // the header termination right (number & type of line terminators)
  383. // so we add it ourselves
  384. //
  385. error = pRequest->AddRequestHeader(
  386. header,
  387. nameLength,
  388. value,
  389. valueLength,
  390. dwModifiers & HTTP_ADDREQ_INDEX_MASK,
  391. dwModifiers & HTTP_ADDREQ_FLAGS_MASK
  392. );
  393. } else {
  394. //
  395. // BUGBUG - we are adding headers, but the header-value is not
  396. // present. This is a somewhat tricky situation because we
  397. // we may have already added some headers, resulting in
  398. // the app not really knowing which headers were good and
  399. // which failed; additionally, one or more of the headers
  400. // may have been added, increasing the apps confusion. The
  401. // best way to handle this (if necessary) is to check the
  402. // header name/value pairs w.r.t. the dwModifiers flags.
  403. // HOWEVER, even then we can get into a state down here
  404. // where we add a couple of headers, then fail...
  405. //
  406. error = ERROR_INVALID_PARAMETER;
  407. }
  408. } while (error == ERROR_SUCCESS);
  409. quit:
  410. DEBUG_LEAVE(error);
  411. return error;
  412. }