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.

846 lines
21 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. rcvhdrs.cxx
  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 PUCHAR pHeader,
  26. IN ULONG HeaderLength,
  27. OUT PULONG pBytesTaken
  28. )
  29. {
  30. UCHAR CurrentChar;
  31. ULONG CurrentOffset;
  32. BOOLEAN HaveHeader;
  33. //
  34. // Important this is above the label (and our of the for loop)
  35. // to support goto repeats.
  36. //
  37. CurrentOffset = 0;
  38. look_for_crlf:
  39. HaveHeader = FALSE;
  40. //
  41. // Always start from the second character.
  42. //
  43. CurrentOffset++;
  44. //
  45. // While we still have data, loop through looking for a CRLF or LFLF pair.
  46. //
  47. for (; CurrentOffset < HeaderLength; CurrentOffset += 2)
  48. {
  49. CurrentChar = *(pHeader + CurrentOffset);
  50. //
  51. // Try CR first because if we hit CR we only need to look at the
  52. // character to the right to see if it is LF. The chance of hitting
  53. // either CF or LF is 50/50, but the path length is shorter in the
  54. // case we hit CR so check it first.
  55. //
  56. if (CurrentChar == CR)
  57. {
  58. //
  59. // Be a bit aggressive to assume we will hit CRLF by adjusting
  60. // CurrentOffset forward. If this is not CRLF, restore it back.
  61. //
  62. CurrentOffset++;
  63. if (CurrentOffset < HeaderLength &&
  64. *(pHeader + CurrentOffset) == LF)
  65. {
  66. //
  67. // Cool, we are done so break the loop.
  68. //
  69. HaveHeader = TRUE;
  70. break;
  71. }
  72. else
  73. {
  74. CurrentOffset--;
  75. }
  76. }
  77. //
  78. // Now check to see if this is LF. If so, we look backward to see
  79. // if we have a CR, and if that is not the case, look forward to
  80. // see if we have another LF. It is assumed CRLF is more common
  81. // than LFLF so we always look backward first.
  82. //
  83. if (CurrentChar == LF)
  84. {
  85. if (*(pHeader + CurrentOffset - 1) == CR)
  86. {
  87. //
  88. // Everything is set so simply break the loop.
  89. //
  90. HaveHeader = TRUE;
  91. break;
  92. }
  93. //
  94. // It is still possible this can be LFLF so verify it.
  95. //
  96. CurrentOffset++;
  97. if (CurrentOffset < HeaderLength &&
  98. *(pHeader + CurrentOffset) == LF)
  99. {
  100. //
  101. // Cool, we are done so break the loop.
  102. //
  103. HaveHeader = TRUE;
  104. break;
  105. }
  106. else
  107. {
  108. CurrentOffset--;
  109. }
  110. }
  111. }
  112. //
  113. // If we found the termination OK, return the length of the value.
  114. //
  115. if (HaveHeader)
  116. {
  117. ASSERT(CurrentOffset < HeaderLength);
  118. //
  119. // OK, we found a CRLF or LFLF, peek ahead 1 char to handle header
  120. // value continuation.
  121. //
  122. //
  123. // Skip the LF.
  124. //
  125. CurrentOffset += 1;
  126. if (CurrentOffset == HeaderLength)
  127. {
  128. //
  129. // Not enough buffer to check, need more.
  130. //
  131. *pBytesTaken = 0;
  132. return STATUS_SUCCESS;
  133. }
  134. CurrentChar = *(pHeader + CurrentOffset);
  135. //
  136. // Is this a second line of the same header value? Check for
  137. // continuation.
  138. //
  139. if (IS_HTTP_LWS(CurrentChar))
  140. {
  141. ASSERT(pHeader[CurrentOffset - 1] == LF);
  142. ASSERT(CurrentOffset >= 2);
  143. //
  144. // Replace the CRLF|LFLF with SPSP.
  145. //
  146. pHeader[CurrentOffset - 1] = SP;
  147. pHeader[CurrentOffset - 2] = SP;
  148. //
  149. // Skip this WS char.
  150. //
  151. CurrentOffset += 1;
  152. //
  153. // Find the real end of the header value.
  154. //
  155. goto look_for_crlf;
  156. }
  157. //
  158. // All done!
  159. //
  160. *pBytesTaken = CurrentOffset;
  161. return STATUS_SUCCESS;
  162. }
  163. //
  164. // Did not find the end of a header, let's get more buffer.
  165. //
  166. *pBytesTaken = 0;
  167. return STATUS_SUCCESS;
  168. }
  169. /*++
  170. Routine Description:
  171. A utility routine, to find the terminating CRLF or LFLF of a
  172. chunk header.
  173. Arguments:
  174. pHeader - Header whose end is to be found.
  175. HeaderLength - Length of data pointed to by pHeader.
  176. TokenLength - Where to return the length of the token.
  177. Return Value:
  178. Length of the header, or 0 if we couldn't find the end.
  179. --*/
  180. NTSTATUS
  181. FindChunkHeaderEnd(
  182. IN PUCHAR pHeader,
  183. IN ULONG HeaderLength,
  184. OUT PULONG pBytesTaken
  185. )
  186. {
  187. UCHAR CurrentChar;
  188. ULONG CurrentOffset;
  189. BOOLEAN HaveCR;
  190. BOOLEAN HaveHeader;
  191. CurrentOffset = 0;
  192. HaveCR = FALSE;
  193. HaveHeader = FALSE;
  194. //
  195. // While we still have data, loop through looking for a CRLF or LFLF pair.
  196. //
  197. for (; CurrentOffset < HeaderLength; CurrentOffset++)
  198. {
  199. CurrentChar = *(pHeader + CurrentOffset);
  200. //
  201. // If this character is a CR or LF, we may be done.
  202. //
  203. if (CurrentChar == CR || CurrentChar == LF)
  204. {
  205. //
  206. // If we've already seen a CR (or LF) immediately preceding this,
  207. // see if this is a LF to terminate the line.
  208. //
  209. if (HaveCR)
  210. {
  211. if (CurrentChar == LF)
  212. {
  213. // It is a LF, so we're done.
  214. HaveHeader = TRUE;
  215. break;
  216. }
  217. // Otherwise, we have a non LF after a CR (or LF). The only
  218. // character this could be is a CR, since we're inside
  219. // the if statement. This could be the start of a CRLF
  220. // sequence, if this is some bizarre LFCRLF or CRCRLF
  221. // sort of thing. Anyway, we don't want to set HaveCR
  222. // to false here.
  223. ASSERT(CurrentChar == CR);
  224. return STATUS_INVALID_DEVICE_REQUEST;
  225. }
  226. else
  227. {
  228. // Otherwise, we haven't seen the start of the terminating pair
  229. // yet, so remember that we now have.
  230. HaveCR = TRUE;
  231. }
  232. }
  233. else if (HaveCR)
  234. {
  235. //
  236. // it's illegal to have CR|LF and non trailing LF.
  237. //
  238. return STATUS_INVALID_DEVICE_REQUEST;
  239. }
  240. }
  241. //
  242. // If we found the termination OK, return the length of the value.
  243. //
  244. if (HaveHeader)
  245. {
  246. ASSERT(CurrentOffset < HeaderLength);
  247. //
  248. // All done!
  249. //
  250. *pBytesTaken = CurrentOffset + 1;
  251. return STATUS_SUCCESS;
  252. }
  253. // Did not find the end of a header, let's get more buffer..
  254. //
  255. *pBytesTaken = 0;
  256. return STATUS_SUCCESS;
  257. }
  258. /*++
  259. Routine Description:
  260. Append a header value to an existing HTTP_HEADER entry, allocating
  261. a buffer and copying the existing buffer.
  262. Arguments:
  263. pHttpHeader - Pointer to HTTP_HEADER structure to append to.
  264. pHeader - Pointer header to be appended.
  265. HeaderLength - Length of data pointed to by pHeader.
  266. Return Value:
  267. TRUE if we succeed, FALSE otherwise.
  268. --*/
  269. NTSTATUS
  270. UlAppendHeaderValue(
  271. PUL_INTERNAL_REQUEST pRequest,
  272. PUL_HTTP_HEADER pHttpHeader,
  273. PUCHAR pHeader,
  274. ULONG HeaderLength
  275. )
  276. {
  277. PUCHAR pNewHeader, pOldHeader;
  278. ULONG OldHeaderLength;
  279. OldHeaderLength = pHttpHeader->HeaderLength;
  280. pNewHeader = UL_ALLOCATE_ARRAY(
  281. NonPagedPool,
  282. UCHAR,
  283. OldHeaderLength + HeaderLength + sizeof(", "), // sizeof gives space
  284. // for the NULL
  285. HEADER_VALUE_POOL_TAG
  286. );
  287. if (pNewHeader == NULL)
  288. {
  289. // Had a failure.
  290. return STATUS_NO_MEMORY;
  291. }
  292. //
  293. // Copy the old data into the new header.
  294. //
  295. RtlCopyMemory(pNewHeader, pHttpHeader->pHeader, OldHeaderLength);
  296. // And copy in the new data as well, seperated by a comma.
  297. //
  298. *(pNewHeader + OldHeaderLength) = ',';
  299. *(pNewHeader + OldHeaderLength + 1) = ' ';
  300. OldHeaderLength += sizeof(", ") - 1;
  301. RtlCopyMemory( pNewHeader + OldHeaderLength, pHeader, HeaderLength);
  302. // Now replace the existing header.
  303. //
  304. pOldHeader = pHttpHeader->pHeader;
  305. pHttpHeader->HeaderLength = OldHeaderLength + HeaderLength;
  306. pHttpHeader->pHeader = pNewHeader;
  307. // If the old header was our buffer, free it too.
  308. //
  309. if (pHttpHeader->OurBuffer)
  310. {
  311. UL_FREE_POOL( pOldHeader, HEADER_VALUE_POOL_TAG );
  312. }
  313. pHttpHeader->OurBuffer = 1;
  314. //
  315. // null terminate it
  316. //
  317. pHttpHeader->pHeader[pHttpHeader->HeaderLength] = ANSI_NULL;
  318. pRequest->HeadersAppended = TRUE;
  319. return STATUS_SUCCESS;
  320. }
  321. /*++
  322. Routine Description:
  323. The default routine for handling headers. Used when we don't want to
  324. do anything with the header but find out if we have the whole thing
  325. and save a pointer to it if we do. this does not allow multiple header
  326. values to exist for this header. use UlMultipleHeaderHandler for
  327. handling that by appending the values together (CSV) .
  328. Arguments:
  329. pHttpConn - HTTP connection on which this header was received.
  330. pHeader - Pointer to the header value.
  331. HeaderLength - Length of data pointed to by pHeader.
  332. HeaderID - ID of the header.
  333. Return Value:
  334. The length of the header value, or 0 if it's not terminated.
  335. --*/
  336. NTSTATUS
  337. UlSingleHeaderHandler(
  338. IN PUL_INTERNAL_REQUEST pRequest,
  339. IN PUCHAR pHeader,
  340. IN ULONG HeaderLength,
  341. IN HTTP_HEADER_ID HeaderID,
  342. OUT PULONG pBytesTaken
  343. )
  344. {
  345. NTSTATUS Status = STATUS_SUCCESS;
  346. ULONG BytesTaken;
  347. ULONG HeaderValueLength;
  348. // Find the end of the header value
  349. //
  350. Status = FindHeaderEnd(
  351. pHeader,
  352. HeaderLength,
  353. &BytesTaken
  354. );
  355. if (NT_SUCCESS(Status) == FALSE)
  356. goto end;
  357. if (BytesTaken > 0)
  358. {
  359. // Strip of the trailing CRLF from the header value length
  360. //
  361. HeaderValueLength = BytesTaken - CRLF_SIZE;
  362. //
  363. // skip any preceding LWS.
  364. //
  365. while (HeaderValueLength > 0 && IS_HTTP_LWS(*pHeader))
  366. {
  367. pHeader++;
  368. HeaderValueLength--;
  369. }
  370. //
  371. // remove any trailing LWS.
  372. //
  373. while (HeaderValueLength > 0 && IS_HTTP_LWS(pHeader[HeaderValueLength-1]))
  374. {
  375. HeaderValueLength--;
  376. }
  377. // do we have an existing header?
  378. //
  379. if (pRequest->HeaderValid[HeaderID] == FALSE)
  380. {
  381. // No existing header, just save this pointer for now.
  382. //
  383. pRequest->HeaderIndex[pRequest->HeaderCount] = (UCHAR)HeaderID;
  384. pRequest->HeaderCount++;
  385. pRequest->HeaderValid[HeaderID] = TRUE;
  386. pRequest->Headers[HeaderID].HeaderLength = HeaderValueLength;
  387. pRequest->Headers[HeaderID].pHeader = pHeader;
  388. pRequest->Headers[HeaderID].OurBuffer = 0;
  389. //
  390. // null terminate it. we have space as all headers end with CRLF.
  391. // we are over-writing the CR
  392. //
  393. pHeader[HeaderValueLength] = ANSI_NULL;
  394. //
  395. // make space for a terminator
  396. //
  397. pRequest->TotalRequestSize += (HeaderValueLength + 1) * sizeof(CHAR);
  398. }
  399. else
  400. {
  401. //
  402. // uh oh. Have an existing header, fail the request.
  403. //
  404. pRequest->ErrorCode = UlErrorHeader;
  405. pRequest->ParseState = ParseErrorState;
  406. UlTrace(PARSER, (
  407. "ul!UlSingleHeaderHandler(pRequest = %p, pHeader = %p)\n"
  408. " ERROR: multiple headers not allowed.\n",
  409. pRequest,
  410. pHeader
  411. ));
  412. Status = STATUS_INVALID_DEVICE_REQUEST;
  413. goto end;
  414. }
  415. }
  416. // Success!
  417. //
  418. *pBytesTaken = BytesTaken;
  419. end:
  420. return Status;
  421. } // UlSingleHeaderHandler
  422. /*++
  423. Routine Description:
  424. The default routine for handling headers. Used when we don't want to
  425. do anything with the header but find out if we have the whole thing
  426. and save a pointer to it if we do. this function handles multiple
  427. headers with the same name, and appends the values together seperated
  428. by commas.
  429. Arguments:
  430. pHttpConn - HTTP connection on which this header was received.
  431. pHeader - Pointer to the header value.
  432. HeaderLength - Length of data pointed to by pHeader.
  433. HeaderID - ID of the header.
  434. Return Value:
  435. The length of the header value, or 0 if it's not terminated.
  436. --*/
  437. NTSTATUS
  438. UlMultipleHeaderHandler(
  439. IN PUL_INTERNAL_REQUEST pRequest,
  440. IN PUCHAR pHeader,
  441. IN ULONG HeaderLength,
  442. IN HTTP_HEADER_ID HeaderID,
  443. OUT PULONG pBytesTaken
  444. )
  445. {
  446. NTSTATUS Status = STATUS_SUCCESS;
  447. ULONG BytesTaken;
  448. ULONG HeaderValueLength;
  449. // Find the end of the header value
  450. //
  451. Status = FindHeaderEnd(
  452. pHeader,
  453. HeaderLength,
  454. &BytesTaken
  455. );
  456. if (NT_SUCCESS(Status) == FALSE)
  457. goto end;
  458. if (BytesTaken > 0)
  459. {
  460. // Strip of the trailing CRLF from the header value length
  461. //
  462. HeaderValueLength = BytesTaken - CRLF_SIZE;
  463. //
  464. // skip any preceding LWS.
  465. //
  466. while (HeaderValueLength > 0 && IS_HTTP_LWS(*pHeader))
  467. {
  468. pHeader++;
  469. HeaderValueLength--;
  470. }
  471. //
  472. // remove any trailing LWS.
  473. //
  474. while (HeaderValueLength > 0 && IS_HTTP_LWS(pHeader[HeaderValueLength-1]))
  475. {
  476. HeaderValueLength--;
  477. }
  478. // do we have an existing header?
  479. //
  480. if (pRequest->HeaderValid[HeaderID] == FALSE)
  481. {
  482. // No existing header, just save this pointer for now.
  483. //
  484. pRequest->HeaderIndex[pRequest->HeaderCount] = (UCHAR)HeaderID;
  485. pRequest->HeaderCount++;
  486. pRequest->HeaderValid[HeaderID] = TRUE;
  487. pRequest->Headers[HeaderID].HeaderLength = HeaderValueLength;
  488. pRequest->Headers[HeaderID].pHeader = pHeader;
  489. pRequest->Headers[HeaderID].OurBuffer = 0;
  490. //
  491. // null terminate it. we have space as all headers end with CRLF.
  492. // we are over-writing the CR
  493. //
  494. pHeader[HeaderValueLength] = ANSI_NULL;
  495. //
  496. // make space for a terminator
  497. //
  498. pRequest->TotalRequestSize += (HeaderValueLength + 1) * sizeof(CHAR);
  499. }
  500. else
  501. {
  502. ULONG OldHeaderLength;
  503. // Have an existing header, append this one.
  504. OldHeaderLength = pRequest->Headers[HeaderID].HeaderLength;
  505. Status = UlAppendHeaderValue(
  506. pRequest,
  507. &pRequest->Headers[HeaderID],
  508. pHeader,
  509. HeaderValueLength
  510. );
  511. if (NT_SUCCESS(Status) == FALSE)
  512. goto end;
  513. //
  514. // Update total request length for the amount we just added.
  515. // space for the terminator is already in there
  516. //
  517. pRequest->TotalRequestSize +=
  518. (pRequest->Headers[HeaderID].HeaderLength - OldHeaderLength) *
  519. sizeof(CHAR);
  520. }
  521. }
  522. // Success!
  523. //
  524. *pBytesTaken = BytesTaken;
  525. end:
  526. return Status;
  527. } // UlMultipleHeaderHandler
  528. /*++
  529. Routine Description:
  530. The routine for handling Accept headers.
  531. Arguments:
  532. pHttpConn - HTTP connection on which this header was received.
  533. pHeader - Pointer to the header value.
  534. HeaderLength - Length of data pointed to by pHeader.
  535. HeaderID - ID of the header.
  536. Return Value:
  537. The length of the header value, or 0 if it's not terminated.
  538. Wildcard bit is set in the request if found
  539. --*/
  540. NTSTATUS
  541. UlAcceptHeaderHandler(
  542. IN PUL_INTERNAL_REQUEST pRequest,
  543. IN PUCHAR pHeader,
  544. IN ULONG HeaderLength,
  545. IN HTTP_HEADER_ID HeaderID,
  546. OUT PULONG pBytesTaken
  547. )
  548. {
  549. NTSTATUS Status = STATUS_SUCCESS;
  550. ULONG BytesTaken;
  551. ULONG HeaderValueLength;
  552. // Find the end of the header value
  553. //
  554. Status = FindHeaderEnd(
  555. pHeader,
  556. HeaderLength,
  557. &BytesTaken
  558. );
  559. if (NT_SUCCESS(Status) == FALSE)
  560. goto end;
  561. if (BytesTaken > 0)
  562. {
  563. // Strip of the trailing CRLF from the header value length
  564. //
  565. HeaderValueLength = BytesTaken - CRLF_SIZE;
  566. //
  567. // skip any preceding LWS.
  568. //
  569. while (HeaderValueLength > 0 && IS_HTTP_LWS(*pHeader))
  570. {
  571. pHeader++;
  572. HeaderValueLength--;
  573. }
  574. //
  575. // remove any trailing LWS.
  576. //
  577. while (HeaderValueLength > 0 && IS_HTTP_LWS(pHeader[HeaderValueLength-1]))
  578. {
  579. HeaderValueLength--;
  580. }
  581. // do we have an existing header?
  582. //
  583. if (pRequest->HeaderValid[HeaderID] == FALSE)
  584. {
  585. // No existing header, just save this pointer for now.
  586. //
  587. pRequest->HeaderIndex[pRequest->HeaderCount] = (UCHAR)HeaderID;
  588. pRequest->HeaderCount++;
  589. pRequest->HeaderValid[HeaderID] = TRUE;
  590. pRequest->Headers[HeaderID].HeaderLength = HeaderValueLength;
  591. pRequest->Headers[HeaderID].pHeader = pHeader;
  592. pRequest->Headers[HeaderID].OurBuffer = 0;
  593. //
  594. // null terminate it. we have space as all headers end with CRLF.
  595. // we are over-writing the CR
  596. //
  597. pHeader[HeaderValueLength] = ANSI_NULL;
  598. //
  599. // make space for a terminator
  600. //
  601. pRequest->TotalRequestSize += (HeaderValueLength + 1) * sizeof(CHAR);
  602. if (HeaderValueLength > WILDCARD_SIZE)
  603. {
  604. //
  605. // for the fast path, we'll check only */* at the end
  606. //
  607. if (
  608. (*(UNALIGNED64 ULONG *) (&pHeader[HeaderValueLength - WILDCARD_SIZE]) == WILDCARD_SPACE) ||
  609. (*(UNALIGNED64 ULONG *) (&pHeader[HeaderValueLength - WILDCARD_SIZE]) == WILDCARD_COMMA)
  610. )
  611. {
  612. pRequest->AcceptWildcard = TRUE;
  613. }
  614. }
  615. }
  616. else
  617. {
  618. ULONG OldHeaderLength;
  619. // Have an existing header, append this one.
  620. OldHeaderLength = pRequest->Headers[HeaderID].HeaderLength;
  621. Status = UlAppendHeaderValue(
  622. pRequest,
  623. &pRequest->Headers[HeaderID],
  624. pHeader,
  625. HeaderValueLength
  626. );
  627. if (NT_SUCCESS(Status) == FALSE)
  628. goto end;
  629. //
  630. // Update total request length for the amount we just added.
  631. // space for the terminator is already in there
  632. //
  633. pRequest->TotalRequestSize +=
  634. (pRequest->Headers[HeaderID].HeaderLength - OldHeaderLength) *
  635. sizeof(CHAR);
  636. }
  637. }
  638. // Success!
  639. //
  640. *pBytesTaken = BytesTaken;
  641. end:
  642. return Status;
  643. } // UlAcceptHeaderHandler