Source code of Windows XP (NT5)
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.

574 lines
15 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. rcvhdrs.c
  5. Abstract:
  6. Contains all of the per header handling code for received headers.
  7. Author:
  8. Henry Sanders (henrysa) 11-May-1998
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #include "rcvhdrs.h"
  13. /*++
  14. Routine Description:
  15. A utility routine, to find the terminating CRLF or LFLF of a header.
  16. Arguments:
  17. pHeader - Header whose end is to be found.
  18. HeaderLength - Length of data pointed to by pHeader.
  19. TokenLength - Where to return the length of the token.
  20. Return Value:
  21. Length of the header, or 0 if we couldn't find the end.
  22. --*/
  23. NTSTATUS
  24. FindHeaderEnd(
  25. IN PUL_INTERNAL_REQUEST pRequest,
  26. IN PUCHAR pHeader,
  27. IN ULONG HeaderLength,
  28. OUT BOOLEAN * pEncodedWord,
  29. OUT ULONG * pBytesTaken
  30. )
  31. {
  32. UCHAR CurrentChar;
  33. ULONG CurrentOffset;
  34. BOOLEAN HaveCR;
  35. BOOLEAN HaveHeader;
  36. BOOLEAN HaveEQ;
  37. BOOLEAN HaveEncodedWord;
  38. // Important this is above the label (and our of the for loop)
  39. // to support goto repeats
  40. //
  41. CurrentOffset = 0;
  42. HaveEncodedWord = FALSE;
  43. look_for_crlf:
  44. HaveCR = FALSE;
  45. HaveEQ = FALSE;
  46. HaveHeader = FALSE;
  47. //
  48. // While we still have data, loop through looking for a CRLF or LFLF pair.
  49. //
  50. for (; CurrentOffset < HeaderLength; CurrentOffset++)
  51. {
  52. CurrentChar = *(pHeader + CurrentOffset);
  53. //
  54. // If this character is a CR or LF, we may be done.
  55. //
  56. if (CurrentChar == CR || CurrentChar == LF)
  57. {
  58. // If we've already seen a CR (or LF) immediately preceding this,
  59. // see if this is a LF to terminate the line.
  60. if (HaveCR)
  61. {
  62. if (CurrentChar == LF)
  63. {
  64. // It is a LF, so we're done.
  65. HaveHeader = TRUE;
  66. break;
  67. }
  68. // Otherwise, we have a non LF after a CR (or LF). The only
  69. // character this could be is a CR, since we're inside
  70. // the if statement. This could be the start of a CRLF
  71. // sequence, if this is some bizarre LFCRLF or CRCRLF
  72. // sort of thing. Anyway, we don't want to set HaveCR
  73. // to false here.
  74. ASSERT(CurrentChar == CR);
  75. //
  76. // paulmcd: this seems wacked. bizarre enough to fail
  77. //
  78. pRequest->ErrorCode = UlErrorCRLF;
  79. pRequest->ParseState = ParseErrorState;
  80. UlTrace(PARSER, (
  81. "ul!FindHeaderEnd(pRequest = %p, pHeader = %p)\n"
  82. " ERROR: don't like to see CRCR\n",
  83. pRequest,
  84. pHeader
  85. ));
  86. return STATUS_INVALID_DEVICE_REQUEST;
  87. }
  88. else
  89. {
  90. // Otherwise, we haven't seen the start of the terminating pair
  91. // yet, so remember that we now have.
  92. HaveCR = TRUE;
  93. }
  94. }
  95. else if (HaveCR)
  96. {
  97. //
  98. // it's illegal to have CR|LF and non trailing LF.
  99. //
  100. pRequest->ErrorCode = UlErrorCRLF;
  101. pRequest->ParseState = ParseErrorState;
  102. UlTrace(PARSER, (
  103. "ul!FindHeaderEnd(pRequest = %p, pHeader = %p)\n"
  104. " ERROR: it's illegal to have CR|LF and non trailing LF.\n",
  105. pRequest,
  106. pHeader
  107. ));
  108. return STATUS_INVALID_DEVICE_REQUEST;
  109. }
  110. else if (HaveEncodedWord == FALSE)
  111. {
  112. // Were looking to see if we have any =? ?= encoded words
  113. // according to rfc2047. we'll decode them later in a
  114. // second pass. thus were not so strict here on format,
  115. // this is simply a hint for perf.
  116. //
  117. if (CurrentChar == '=')
  118. {
  119. HaveEQ = TRUE;
  120. }
  121. else if (CurrentChar == '?')
  122. {
  123. if (HaveEQ)
  124. HaveEncodedWord = TRUE;
  125. }
  126. else
  127. HaveEQ = FALSE;
  128. }
  129. }
  130. // If we found the termination OK, return the length of the value.
  131. //
  132. if (HaveHeader)
  133. {
  134. ASSERT(CurrentOffset < HeaderLength);
  135. // ok, we found a CRLF or LFLF, peek ahead 1 char to
  136. // handle header value continuation
  137. //
  138. // Skip the LF
  139. //
  140. CurrentOffset += 1;
  141. if (CurrentOffset == HeaderLength)
  142. {
  143. // not enough buffer to check, need more
  144. //
  145. *pBytesTaken = 0;
  146. return STATUS_SUCCESS;
  147. }
  148. CurrentChar = *(pHeader + CurrentOffset);
  149. // is this a second line of the same header value? check for continuation
  150. //
  151. if (IS_HTTP_LWS(CurrentChar))
  152. {
  153. ASSERT(pHeader[CurrentOffset-1] == LF);
  154. ASSERT(CurrentOffset >= 2);
  155. // Replace the CRLF|LFLF with SPSP
  156. //
  157. pHeader[CurrentOffset-1] = SP;
  158. pHeader[CurrentOffset-2] = SP;
  159. // Skip this WS char
  160. //
  161. CurrentOffset += 1;
  162. // Find the real end of the header value
  163. //
  164. goto look_for_crlf;
  165. }
  166. // All done!
  167. //
  168. *pEncodedWord = HaveEncodedWord;
  169. *pBytesTaken = CurrentOffset;
  170. return STATUS_SUCCESS;
  171. }
  172. // Did not find the end of a header, let's get more buffer..
  173. //
  174. *pBytesTaken = 0;
  175. return STATUS_SUCCESS;
  176. }
  177. /*++
  178. Routine Description:
  179. Append a header value to an existing HTTP_HEADER entry, allocating
  180. a buffer and copying the existing buffer.
  181. Arguments:
  182. pHttpHeader - Pointer to HTTP_HEADER structure to append to.
  183. pHeader - Pointer header to be appended.
  184. HeaderLength - Length of data pointed to by pHeader.
  185. Return Value:
  186. TRUE if we succeed, FALSE otherwise.
  187. --*/
  188. NTSTATUS
  189. AppendHeaderValue(
  190. PUL_HTTP_HEADER pHttpHeader,
  191. PUCHAR pHeader,
  192. ULONG HeaderLength
  193. )
  194. {
  195. PUCHAR pNewHeader, pOldHeader;
  196. ULONG OldHeaderLength;
  197. OldHeaderLength = pHttpHeader->HeaderLength;
  198. pNewHeader = UL_ALLOCATE_ARRAY(
  199. NonPagedPool,
  200. UCHAR,
  201. OldHeaderLength + HeaderLength + sizeof(", "), // sizeof gives space
  202. // for the NULL
  203. UL_KNOWN_HEADER_POOL_TAG
  204. );
  205. if (pNewHeader == NULL)
  206. {
  207. // Had a failure.
  208. return STATUS_NO_MEMORY;
  209. }
  210. //
  211. // Copy the old data into the new header.
  212. //
  213. RtlCopyMemory(pNewHeader, pHttpHeader->pHeader, OldHeaderLength);
  214. // And copy in the new data as well, seperated by a comma.
  215. //
  216. *(pNewHeader + OldHeaderLength) = ',';
  217. *(pNewHeader + OldHeaderLength + 1) = ' ';
  218. OldHeaderLength += sizeof(", ") - 1;
  219. RtlCopyMemory( pNewHeader + OldHeaderLength, pHeader, HeaderLength);
  220. // Now replace the existing header.
  221. //
  222. pOldHeader = pHttpHeader->pHeader;
  223. pHttpHeader->HeaderLength = OldHeaderLength + HeaderLength;
  224. pHttpHeader->pHeader = pNewHeader;
  225. // If the old header was our buffer, free it too.
  226. //
  227. if (pHttpHeader->OurBuffer)
  228. {
  229. UL_FREE_POOL( pOldHeader, UL_KNOWN_HEADER_POOL_TAG );
  230. }
  231. pHttpHeader->OurBuffer = 1;
  232. //
  233. // null terminate it
  234. //
  235. pHttpHeader->pHeader[pHttpHeader->HeaderLength] = ANSI_NULL;
  236. return STATUS_SUCCESS;
  237. }
  238. /*++
  239. Routine Description:
  240. The default routine for handling headers. Used when we don't want to
  241. do anything with the header but find out if we have the whole thing
  242. and save a pointer to it if we do. this does not allow multiple header
  243. values to exist for this header. use MultipleHeaderHandler for
  244. handling that by appending the values together (CSV) .
  245. Arguments:
  246. pHttpConn - HTTP connection on which this header was received.
  247. pHeader - Pointer to the header value.
  248. HeaderLength - Length of data pointed to by pHeader.
  249. HeaderID - ID of the header.
  250. Return Value:
  251. The length of the header value, or 0 if it's not terminated.
  252. --*/
  253. NTSTATUS
  254. SingleHeaderHandler(
  255. IN PUL_INTERNAL_REQUEST pRequest,
  256. IN PUCHAR pHeader,
  257. IN ULONG HeaderLength,
  258. IN HTTP_HEADER_ID HeaderID,
  259. OUT ULONG * pBytesTaken
  260. )
  261. {
  262. NTSTATUS Status = STATUS_SUCCESS;
  263. ULONG BytesTaken;
  264. ULONG HeaderValueLength;
  265. BOOLEAN EncodedWord;
  266. // Find the end of the header value
  267. //
  268. Status = FindHeaderEnd(
  269. pRequest,
  270. pHeader,
  271. HeaderLength,
  272. &EncodedWord,
  273. &BytesTaken
  274. );
  275. if (NT_SUCCESS(Status) == FALSE)
  276. goto end;
  277. if (BytesTaken > 0)
  278. {
  279. // Strip of the trailing CRLF from the header value length
  280. //
  281. HeaderValueLength = BytesTaken - CRLF_SIZE;
  282. //
  283. // skip any preceding LWS.
  284. //
  285. while (HeaderValueLength > 0 && IS_HTTP_LWS(*pHeader))
  286. {
  287. pHeader++;
  288. HeaderValueLength--;
  289. }
  290. //
  291. // Was it encoded at all?
  292. //
  293. pRequest->Headers[HeaderID].Encoded = EncodedWord ? 1 : 0;
  294. // do we have an existing header?
  295. //
  296. if (pRequest->Headers[HeaderID].Valid == 0)
  297. {
  298. // No existing header, just save this pointer for now.
  299. //
  300. pRequest->Headers[HeaderID].Valid = 1;
  301. pRequest->Headers[HeaderID].HeaderLength = HeaderValueLength;
  302. pRequest->Headers[HeaderID].pHeader = pHeader;
  303. //
  304. // null terminate it. we have space as all headers end with CRLF.
  305. // we are over-writing the CR
  306. //
  307. pHeader[HeaderValueLength] = ANSI_NULL;
  308. //
  309. // make space for a terminator
  310. //
  311. pRequest->TotalRequestSize += (HeaderValueLength + 1) * sizeof(WCHAR);
  312. }
  313. else
  314. {
  315. //
  316. // uh oh. Have an existing header, fail the request.
  317. //
  318. pRequest->ErrorCode = UlErrorHeader;
  319. pRequest->ParseState = ParseErrorState;
  320. UlTrace(PARSER, (
  321. "ul!SingleHeaderHandler(pRequest = %p, pHeader = %p)\n"
  322. " ERROR: multiple headers not allowed.\n",
  323. pRequest,
  324. pHeader
  325. ));
  326. Status = STATUS_INVALID_DEVICE_REQUEST;
  327. goto end;
  328. }
  329. }
  330. // Success!
  331. //
  332. *pBytesTaken = BytesTaken;
  333. end:
  334. return Status;
  335. } // SingleHeaderHandler
  336. /*++
  337. Routine Description:
  338. The default routine for handling headers. Used when we don't want to
  339. do anything with the header but find out if we have the whole thing
  340. and save a pointer to it if we do. this function handles multiple
  341. headers with the same name, and appends the values together seperated
  342. by commas.
  343. Arguments:
  344. pHttpConn - HTTP connection on which this header was received.
  345. pHeader - Pointer to the header value.
  346. HeaderLength - Length of data pointed to by pHeader.
  347. HeaderID - ID of the header.
  348. Return Value:
  349. The length of the header value, or 0 if it's not terminated.
  350. --*/
  351. NTSTATUS
  352. MultipleHeaderHandler(
  353. IN PUL_INTERNAL_REQUEST pRequest,
  354. IN PUCHAR pHeader,
  355. IN ULONG HeaderLength,
  356. IN HTTP_HEADER_ID HeaderID,
  357. OUT ULONG * pBytesTaken
  358. )
  359. {
  360. NTSTATUS Status = STATUS_SUCCESS;
  361. ULONG BytesTaken;
  362. ULONG HeaderValueLength;
  363. BOOLEAN EncodedWord;
  364. // Find the end of the header value
  365. //
  366. Status = FindHeaderEnd(
  367. pRequest,
  368. pHeader,
  369. HeaderLength,
  370. &EncodedWord,
  371. &BytesTaken
  372. );
  373. if (NT_SUCCESS(Status) == FALSE)
  374. goto end;
  375. if (BytesTaken > 0)
  376. {
  377. // Strip of the trailing CRLF from the header value length
  378. //
  379. HeaderValueLength = BytesTaken - CRLF_SIZE;
  380. //
  381. // skip any preceding LWS.
  382. //
  383. while (HeaderValueLength > 0 && IS_HTTP_LWS(*pHeader))
  384. {
  385. pHeader++;
  386. HeaderValueLength--;
  387. }
  388. //
  389. // Was it encoded at all?
  390. //
  391. pRequest->Headers[HeaderID].Encoded = EncodedWord ? 1 : 0;
  392. // do we have an existing header?
  393. //
  394. if (pRequest->Headers[HeaderID].Valid == 0)
  395. {
  396. // No existing header, just save this pointer for now.
  397. //
  398. pRequest->Headers[HeaderID].Valid = 1;
  399. pRequest->Headers[HeaderID].HeaderLength = HeaderValueLength;
  400. pRequest->Headers[HeaderID].pHeader = pHeader;
  401. //
  402. // null terminate it. we have space as all headers end with CRLF.
  403. // we are over-writing the CR
  404. //
  405. pHeader[HeaderValueLength] = ANSI_NULL;
  406. //
  407. // make space for a terminator
  408. //
  409. pRequest->TotalRequestSize += (HeaderValueLength + 1) * sizeof(WCHAR);
  410. }
  411. else
  412. {
  413. ULONG OldHeaderLength;
  414. // Have an existing header, append this one.
  415. OldHeaderLength = pRequest->Headers[HeaderID].HeaderLength;
  416. Status = AppendHeaderValue(
  417. &pRequest->Headers[HeaderID],
  418. pHeader,
  419. HeaderValueLength
  420. );
  421. if (NT_SUCCESS(Status) == FALSE)
  422. goto end;
  423. //
  424. // Update total request length for the amount we just added.
  425. // space for the terminator is already in there
  426. //
  427. pRequest->TotalRequestSize +=
  428. (pRequest->Headers[HeaderID].HeaderLength - OldHeaderLength) *
  429. sizeof(WCHAR);
  430. }
  431. }
  432. // Success!
  433. //
  434. *pBytesTaken = BytesTaken;
  435. end:
  436. return Status;
  437. } // MultipleHeaderHandler