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.

3307 lines
108 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. ucrcv.c
  5. Abstract:
  6. Contains the code that parses incoming HTTP responses. We have
  7. to handle the following cases.
  8. - Pipelined responses (an indication has more than one response).
  9. - Batched TDI receives (response split across TDI indications).
  10. - App does not have sufficent buffer space to hold the parsed
  11. response.
  12. - Differnet types of encoding.
  13. - Efficient parsing.
  14. We try to minimize the number of buffer copies. In the best case,
  15. we parse directly into the app's buffer. The best case is achieved
  16. when the app has passed output buffer in the HttpSendRequest() call.
  17. Also contains all of the per-header handling code for received headers.
  18. Author:
  19. Rajesh Sundaram (rajeshsu), 25th Aug 2000
  20. Revision History:
  21. --*/
  22. #include "precomp.h"
  23. #include "ucparse.h"
  24. #ifdef ALLOC_PRAGMA
  25. //
  26. // None of these routines are PAGEABLE since we are parsing at DPC.
  27. //
  28. #pragma alloc_text( PAGEUC, UcpGetResponseBuffer)
  29. #pragma alloc_text( PAGEUC, UcpMergeIndications)
  30. #pragma alloc_text( PAGEUC, UcpParseHttpResponse)
  31. #pragma alloc_text( PAGEUC, UcHandleResponse)
  32. #pragma alloc_text( PAGEUC, UcpHandleConnectVerbFailure)
  33. #pragma alloc_text( PAGEUC, UcpHandleParsedRequest)
  34. #pragma alloc_text( PAGEUC, UcpCarveDataChunk)
  35. #pragma alloc_text( PAGEUC, UcpCopyEntityToDataChunk )
  36. #pragma alloc_text( PAGEUC, UcpReferenceForReceive )
  37. #pragma alloc_text( PAGEUC, UcpDereferenceForReceive )
  38. #pragma alloc_text( PAGEUC, UcpCopyHttpResponseHeaders )
  39. #pragma alloc_text( PAGEUC, UcpExpandResponseBuffer )
  40. #pragma alloc_text( PAGEUC, UcpCompleteReceiveResponseIrp )
  41. #endif
  42. //
  43. // Private Functions.
  44. //
  45. /***************************************************************************++
  46. Routine Description:
  47. This routine carves a HTTP_DATA_CHUNK in the HTTP_RESPONSE structure and
  48. adjusts all the pointers in the UC_HTTP_REQUEST structure.
  49. Arguments:
  50. pResponse - The HTTP_RESPONSE
  51. pRequest - The internal HTTP request.
  52. pIndication - pointer to buffer
  53. BytesIndicated - buffer length to be written.
  54. AlignLength - The align'd length for pointer manipulations.
  55. Return Value:
  56. STATUS_SUCCESS - Successfully copied.
  57. STATUS_INTEGER_OVERFLOW - Entity chunk overflow
  58. --***************************************************************************/
  59. NTSTATUS
  60. _inline
  61. UcpCarveDataChunk(
  62. IN PHTTP_RESPONSE pResponse,
  63. IN PUC_HTTP_REQUEST pRequest,
  64. IN PUCHAR pIndication,
  65. IN ULONG BytesIndicated,
  66. IN ULONG AlignLength
  67. )
  68. {
  69. USHORT j;
  70. PUCHAR pBuffer;
  71. ASSERT(AlignLength == ALIGN_UP(BytesIndicated, PVOID));
  72. j = pResponse->EntityChunkCount;
  73. if((pResponse->EntityChunkCount + 1) < j)
  74. {
  75. return STATUS_INTEGER_OVERFLOW;
  76. }
  77. pResponse->EntityChunkCount++;
  78. pBuffer = pRequest->CurrentBuffer.pOutBufferTail - AlignLength;
  79. pResponse->pEntityChunks[j].FromMemory.BufferLength = BytesIndicated;
  80. pResponse->pEntityChunks[j].FromMemory.pBuffer = pBuffer;
  81. RtlCopyMemory(
  82. pBuffer,
  83. pIndication,
  84. BytesIndicated
  85. );
  86. pRequest->CurrentBuffer.pOutBufferHead += sizeof(HTTP_DATA_CHUNK);
  87. pRequest->CurrentBuffer.pOutBufferTail -= AlignLength;
  88. pRequest->CurrentBuffer.BytesAvailable -= (sizeof(HTTP_DATA_CHUNK) +
  89. AlignLength);
  90. return STATUS_SUCCESS;
  91. }
  92. /***************************************************************************++
  93. Routine Description:
  94. This routine carves a HTTP_DATA_CHUNK in the HTTP_RESPONSE structure and
  95. adjusts all the pointers in the UC_HTTP_REQUEST structure.
  96. Arguments:
  97. pRequest - The internal HTTP request.
  98. BytesToTake - Bytes we want to consume.
  99. BytesIndicated - Total no of bytes indicated by TDI.
  100. pIndication - pointer to buffer
  101. pBytesTaken - Bytes we consumed.
  102. Return Value:
  103. UcDataChunkCopyAll : We copied of BytesToTake into a HTTP_DATA_CHUNK
  104. UcDataChunkCopyPartial: We copied some of BytesToTake into HTTP_DATA_CHUNK
  105. --***************************************************************************/
  106. UC_DATACHUNK_RETURN
  107. UcpCopyEntityToDataChunk(
  108. IN PHTTP_RESPONSE pResponse,
  109. IN PUC_HTTP_REQUEST pRequest,
  110. IN ULONG BytesToTake,
  111. IN ULONG BytesIndicated,
  112. IN PUCHAR pIndication,
  113. OUT PULONG pBytesTaken
  114. )
  115. {
  116. ULONG AlignLength;
  117. *pBytesTaken = 0;
  118. if(BytesToTake == 0)
  119. {
  120. // What's the point in creating a 0 length chunk?
  121. //
  122. return UcDataChunkCopyAll;
  123. }
  124. if(BytesToTake > BytesIndicated)
  125. {
  126. // We don't want to exceed the amount that is indicated by TDI.
  127. //
  128. BytesToTake = BytesIndicated;
  129. }
  130. AlignLength = ALIGN_UP(BytesToTake, PVOID);
  131. if(pRequest->CurrentBuffer.BytesAvailable >=
  132. AlignLength + sizeof(HTTP_DATA_CHUNK))
  133. {
  134. // There is enough out buffer space to consume the indicated data
  135. //
  136. if(UcpCarveDataChunk(
  137. pResponse,
  138. pRequest,
  139. pIndication,
  140. BytesToTake,
  141. AlignLength
  142. ) == STATUS_SUCCESS)
  143. {
  144. *pBytesTaken += BytesToTake;
  145. return UcDataChunkCopyAll;
  146. }
  147. }
  148. else if(pRequest->CurrentBuffer.BytesAvailable > sizeof(HTTP_DATA_CHUNK))
  149. {
  150. ULONG Size = pRequest->CurrentBuffer.BytesAvailable -
  151. sizeof(HTTP_DATA_CHUNK);
  152. AlignLength = ALIGN_DOWN(Size, PVOID);
  153. if(0 != AlignLength)
  154. {
  155. if(UcpCarveDataChunk(pResponse,
  156. pRequest,
  157. pIndication,
  158. AlignLength,
  159. AlignLength
  160. ) == STATUS_SUCCESS)
  161. {
  162. *pBytesTaken += AlignLength;
  163. }
  164. }
  165. }
  166. return UcDataChunkCopyPartial;
  167. }
  168. /**************************************************************************++
  169. Routine Description:
  170. This routine is called when we have a parsed response buffer that can be
  171. copied to a Receive Response IRP.
  172. Arguments:
  173. pRequest - The Request
  174. OldIrql - The IRQL at which the connection spin lock was acquired.
  175. Return Value:
  176. None.
  177. --**************************************************************************/
  178. VOID
  179. UcpCompleteReceiveResponseIrp(
  180. IN PUC_HTTP_REQUEST pRequest,
  181. IN KIRQL OldIrql
  182. )
  183. {
  184. NTSTATUS Status;
  185. PIRP pIrp;
  186. PIO_STACK_LOCATION pIrpSp;
  187. ULONG OutBufferLen;
  188. ULONG BytesTaken;
  189. PUC_HTTP_RECEIVE_RESPONSE pHttpResponse;
  190. LIST_ENTRY TmpIrpList;
  191. PLIST_ENTRY pListEntry;
  192. PUC_RESPONSE_BUFFER pTmpBuffer;
  193. //
  194. // Sanity check
  195. //
  196. ASSERT(UC_IS_VALID_HTTP_REQUEST(pRequest));
  197. ASSERT(UlDbgSpinLockOwned(&pRequest->pConnection->SpinLock));
  198. //
  199. // Initialize locals.
  200. //
  201. pIrp = NULL;
  202. pIrpSp = NULL;
  203. pHttpResponse = NULL;
  204. Status = STATUS_INVALID_PARAMETER;
  205. //
  206. // Initially no App's IRP to complete.
  207. //
  208. InitializeListHead(&TmpIrpList);
  209. //
  210. // If there is a Receive Response IRP waiting, try to complete it now.
  211. //
  212. Retry:
  213. if (!IsListEmpty(&pRequest->ReceiveResponseIrpList))
  214. {
  215. pListEntry = RemoveHeadList(&pRequest->ReceiveResponseIrpList);
  216. pHttpResponse = CONTAINING_RECORD(pListEntry,
  217. UC_HTTP_RECEIVE_RESPONSE,
  218. Linkage);
  219. if (UcRemoveRcvRespCancelRoutine(pHttpResponse))
  220. {
  221. //
  222. // This IRP has already got cancelled, let's move on
  223. //
  224. InitializeListHead(&pHttpResponse->Linkage);
  225. goto Retry;
  226. }
  227. pIrp = pHttpResponse->pIrp;
  228. pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
  229. OutBufferLen = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  230. //
  231. // Find parsed response buffers to copy to this IRP's buffer
  232. //
  233. Status = UcFindBuffersForReceiveResponseIrp(
  234. pRequest,
  235. OutBufferLen,
  236. TRUE,
  237. &pHttpResponse->ResponseBufferList,
  238. &BytesTaken);
  239. switch(Status)
  240. {
  241. case STATUS_INVALID_PARAMETER:
  242. case STATUS_PENDING:
  243. //
  244. // There must be at least one buffer available for copying
  245. //
  246. ASSERT(FALSE);
  247. break;
  248. case STATUS_BUFFER_TOO_SMALL:
  249. //
  250. // This IRP is too small to hold the parsed response.
  251. //
  252. pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  253. //
  254. // Note that since this is async completion, the IO mgr
  255. // will make the Information field available to the app.
  256. //
  257. pIrp->IoStatus.Information = BytesTaken;
  258. InsertTailList(&TmpIrpList, &pHttpResponse->Linkage);
  259. goto Retry;
  260. case STATUS_SUCCESS:
  261. //
  262. // We got buffers to copy...
  263. //
  264. break;
  265. default:
  266. ASSERT(FALSE);
  267. break;
  268. }
  269. }
  270. //
  271. // Do the dirty work outside the spinlock.
  272. //
  273. UlReleaseSpinLock(&pRequest->pConnection->SpinLock, OldIrql);
  274. if (Status == STATUS_SUCCESS)
  275. {
  276. //
  277. // We found an IPR and parsed response buffers to copy to the IRP.
  278. // Copy the parsed response buffers and complete the IRP
  279. //
  280. BOOLEAN bDone;
  281. //
  282. // Copy parsed response buffers to the IRP
  283. //
  284. Status = UcCopyResponseToIrp(pIrp,
  285. &pHttpResponse->ResponseBufferList,
  286. &bDone,
  287. &BytesTaken);
  288. //
  289. // The request must not be done right now!
  290. //
  291. ASSERT(bDone == FALSE);
  292. pIrp->IoStatus.Status = Status;
  293. pIrp->IoStatus.Information = BytesTaken;
  294. //
  295. // Queue the IRP for completion
  296. //
  297. InsertTailList(&TmpIrpList, &pHttpResponse->Linkage);
  298. //
  299. // Free parsed response buffers
  300. //
  301. while (!IsListEmpty(&pHttpResponse->ResponseBufferList))
  302. {
  303. pListEntry = RemoveHeadList(&pHttpResponse->ResponseBufferList);
  304. pTmpBuffer = CONTAINING_RECORD(pListEntry,
  305. UC_RESPONSE_BUFFER,
  306. Linkage);
  307. ASSERT(IS_VALID_UC_RESPONSE_BUFFER(pTmpBuffer));
  308. UL_FREE_POOL_WITH_QUOTA(pTmpBuffer,
  309. UC_RESPONSE_APP_BUFFER_POOL_TAG,
  310. NonPagedPool,
  311. pTmpBuffer->BytesAllocated,
  312. pRequest->pServerInfo->pProcess);
  313. }
  314. }
  315. //
  316. // Complete Receive Response IRP's
  317. //
  318. while(!IsListEmpty(&TmpIrpList))
  319. {
  320. pListEntry = RemoveHeadList(&TmpIrpList);
  321. pHttpResponse = CONTAINING_RECORD(pListEntry,
  322. UC_HTTP_RECEIVE_RESPONSE,
  323. Linkage);
  324. UlCompleteRequest(pHttpResponse->pIrp, IO_NETWORK_INCREMENT);
  325. UL_FREE_POOL_WITH_QUOTA(pHttpResponse,
  326. UC_HTTP_RECEIVE_RESPONSE_POOL_TAG,
  327. NonPagedPool,
  328. sizeof(UC_HTTP_RECEIVE_RESPONSE),
  329. pRequest->pServerInfo->pProcess);
  330. UC_DEREFERENCE_REQUEST(pRequest);
  331. }
  332. }
  333. /**************************************************************************++
  334. Routine Description:
  335. This routine copies one response buffer to a new (must be bigger)
  336. response buffer.
  337. We make sure that all response headers are stored in a single response
  338. buffer. When a buffer is found to be too small to contain all the
  339. headers, a new bigger buffer is allocated. This routine is then called
  340. to copy old buffer into the new buffer. Bufer layout:
  341. HTTP_RESPONSE Reason Unknown Header Known Header Unknown Header
  342. | String array Values Name/Values
  343. | | | | |
  344. V V V V V
  345. +---------------------------------------------------------------------+
  346. | | | |\\\\\\\| | |
  347. +---------------------------------------------------------------------+
  348. ^ ^
  349. Head Tail
  350. Arguments:
  351. pNewResponse - New response buffer
  352. pOldResponse - Old response buffer
  353. ppBufferHead - Pointer to pointer to top of the free buffer space
  354. ppBufferTail - Pointer to pointer to bottom of the free buffer space
  355. Return Value:
  356. None.
  357. --**************************************************************************/
  358. VOID
  359. UcpCopyHttpResponseHeaders(
  360. PHTTP_RESPONSE pNewResponse,
  361. PHTTP_RESPONSE pOldResponse,
  362. PUCHAR *ppBufferHead,
  363. PUCHAR *ppBufferTail
  364. )
  365. {
  366. USHORT i;
  367. PUCHAR pBufferHead, pBufferTail;
  368. //
  369. // Sanity check
  370. //
  371. ASSERT(pNewResponse);
  372. ASSERT(pOldResponse);
  373. ASSERT(ppBufferHead && *ppBufferHead);
  374. ASSERT(ppBufferTail && *ppBufferTail);
  375. //
  376. // Initialize locals
  377. //
  378. pBufferHead = *ppBufferHead;
  379. pBufferTail = *ppBufferTail;
  380. //
  381. // First, copy the HTTP_RESPONSE structure.
  382. //
  383. RtlCopyMemory(pNewResponse, pOldResponse, sizeof(HTTP_RESPONSE));
  384. //
  385. // Then, copy the Reason string, if any
  386. //
  387. if (pNewResponse->ReasonLength)
  388. {
  389. pNewResponse->pReason = (PCSTR)pBufferHead;
  390. RtlCopyMemory((PUCHAR)pNewResponse->pReason,
  391. (PUCHAR)pOldResponse->pReason,
  392. pNewResponse->ReasonLength);
  393. pBufferHead += pNewResponse->ReasonLength;
  394. }
  395. //
  396. // Copy unknown headers, if any
  397. //
  398. pBufferHead = ALIGN_UP_POINTER(pBufferHead, PVOID);
  399. pNewResponse->Headers.pUnknownHeaders = (PHTTP_UNKNOWN_HEADER)pBufferHead;
  400. if (pNewResponse->Headers.UnknownHeaderCount)
  401. {
  402. pBufferHead = (PUCHAR)((PHTTP_UNKNOWN_HEADER)pBufferHead +
  403. pNewResponse->Headers.UnknownHeaderCount);
  404. for (i = 0; i < pNewResponse->Headers.UnknownHeaderCount; i++)
  405. {
  406. ASSERT(pOldResponse->Headers.pUnknownHeaders[i].pName);
  407. ASSERT(pOldResponse->Headers.pUnknownHeaders[i].NameLength);
  408. ASSERT(pOldResponse->Headers.pUnknownHeaders[i].pRawValue);
  409. ASSERT(pOldResponse->Headers.pUnknownHeaders[i].RawValueLength);
  410. //
  411. // Copy HTTP_UNKNOWN_HEADER structure
  412. //
  413. RtlCopyMemory(&pNewResponse->Headers.pUnknownHeaders[i],
  414. &pOldResponse->Headers.pUnknownHeaders[i],
  415. sizeof(HTTP_UNKNOWN_HEADER));
  416. //
  417. // Make space for unknown header name
  418. //
  419. pBufferTail -= pNewResponse->Headers.pUnknownHeaders[i].NameLength;
  420. pNewResponse->Headers.pUnknownHeaders[i].pName =(PCSTR)pBufferTail;
  421. //
  422. // Copy unknown header name
  423. //
  424. RtlCopyMemory(
  425. (PUCHAR)pNewResponse->Headers.pUnknownHeaders[i].pName,
  426. (PUCHAR)pOldResponse->Headers.pUnknownHeaders[i].pName,
  427. pNewResponse->Headers.pUnknownHeaders[i].NameLength);
  428. //
  429. // Make space for unknown header value
  430. //
  431. pBufferTail -=
  432. pNewResponse->Headers.pUnknownHeaders[i].RawValueLength;
  433. pNewResponse->Headers.pUnknownHeaders[i].pRawValue =
  434. (PCSTR)pBufferTail;
  435. //
  436. // Copy unknow header value
  437. //
  438. RtlCopyMemory(
  439. (PUCHAR)pNewResponse->Headers.pUnknownHeaders[i].pRawValue,
  440. (PUCHAR)pOldResponse->Headers.pUnknownHeaders[i].pRawValue,
  441. pNewResponse->Headers.pUnknownHeaders[i].RawValueLength);
  442. }
  443. }
  444. //
  445. // Copy known headers.
  446. //
  447. for (i = 0; i < HttpHeaderResponseMaximum; i++)
  448. {
  449. if (pNewResponse->Headers.KnownHeaders[i].RawValueLength)
  450. {
  451. //
  452. // Make space for known header value
  453. //
  454. pBufferTail -=pNewResponse->Headers.KnownHeaders[i].RawValueLength;
  455. pNewResponse->Headers.KnownHeaders[i].pRawValue =
  456. (PCSTR)pBufferTail;
  457. //
  458. // Copy known header value
  459. //
  460. RtlCopyMemory(
  461. (PUCHAR)pNewResponse->Headers.KnownHeaders[i].pRawValue,
  462. (PUCHAR)pOldResponse->Headers.KnownHeaders[i].pRawValue,
  463. pNewResponse->Headers.KnownHeaders[i].RawValueLength);
  464. }
  465. }
  466. //
  467. // There should not be any entities
  468. //
  469. ASSERT(pNewResponse->EntityChunkCount == 0);
  470. ASSERT(pNewResponse->pEntityChunks == NULL);
  471. //
  472. // Return head and tail pointers
  473. //
  474. *ppBufferHead = pBufferHead;
  475. *ppBufferTail = pBufferTail;
  476. }
  477. /**************************************************************************++
  478. Routine Description:
  479. This routine allocates a new UC_RESPONSE_BUFFER and copies the current
  480. UC_RESPONSE_BUFFER to this new buffer. This routine is called when
  481. we run out of buffer space while parsing response headers. Since all
  482. the headers must be present into a single buffer, a new buffer is
  483. allocated.
  484. Arguments:
  485. pRequest - The Request
  486. BytesIndicated - The number of bytes indicated by TDI.
  487. pResponseBufferFlags - Flags the new buffer must have.
  488. Return Value:
  489. NTSTATUS
  490. --**************************************************************************/
  491. NTSTATUS
  492. UcpExpandResponseBuffer(
  493. IN PUC_HTTP_REQUEST pRequest,
  494. IN ULONG BytesIndicated,
  495. IN ULONG ResponseBufferFlags
  496. )
  497. {
  498. PUC_RESPONSE_BUFFER pInternalBuffer;
  499. ULONG BytesToAllocate;
  500. ULONGLONG TmpLength;
  501. PUCHAR pBufferHead, pBufferTail;
  502. PUCHAR pTmpHead, pTmpTail;
  503. PUC_CLIENT_CONNECTION pConnection;
  504. KIRQL OldIrql;
  505. PIRP pIrp;
  506. //
  507. // Client connection
  508. //
  509. pConnection = pRequest->pConnection;
  510. ASSERT(UC_IS_VALID_CLIENT_CONNECTION(pConnection));
  511. //
  512. // Allocate a new 2 times bigger buffer that can contain all
  513. // response headers. (hopefully!)
  514. //
  515. //
  516. // pRequest->CurrentBuffer.BytesAllocated contains the buffer length
  517. // in both case: case 1, we're using App's buffer OR
  518. // case 2, we're using Driver allocated buffer.
  519. //
  520. TmpLength = 2 * (pRequest->CurrentBuffer.BytesAllocated + BytesIndicated)
  521. + sizeof(UC_RESPONSE_BUFFER);
  522. //
  523. // Align up. Is there ALIGN_UP for ULONGLONG?
  524. //
  525. TmpLength = (TmpLength+sizeof(PVOID)-1) & (~((ULONGLONG)sizeof(PVOID)-1));
  526. BytesToAllocate = (ULONG)TmpLength;
  527. //
  528. // Check for Arithmetic Overflow.
  529. //
  530. if (TmpLength == BytesToAllocate)
  531. {
  532. //
  533. // No arithmetic overflow. Try allocating memory.
  534. //
  535. pInternalBuffer = (PUC_RESPONSE_BUFFER)
  536. UL_ALLOCATE_POOL_WITH_QUOTA(
  537. NonPagedPool,
  538. BytesToAllocate,
  539. UC_RESPONSE_APP_BUFFER_POOL_TAG,
  540. pRequest->pServerInfo->pProcess);
  541. }
  542. else
  543. {
  544. //
  545. // There was an Overflow in the above computation of TmpLength.
  546. // We can't handle more than 4GB of headers.
  547. //
  548. pInternalBuffer = NULL;
  549. }
  550. if (pInternalBuffer == NULL)
  551. {
  552. //
  553. // Either there was an arithmetic overflow or memory allocation
  554. // failed. In both cases, return error.
  555. //
  556. return STATUS_INSUFFICIENT_RESOURCES;
  557. }
  558. //
  559. // Initialize pInternalBuffer
  560. //
  561. RtlZeroMemory(pInternalBuffer, sizeof(UC_RESPONSE_BUFFER));
  562. pInternalBuffer->Signature = UC_RESPONSE_BUFFER_SIGNATURE;
  563. pInternalBuffer->BytesAllocated = BytesToAllocate;
  564. //
  565. // Header buffer is not mergeable with previous buffers.
  566. //
  567. pInternalBuffer->Flags = ResponseBufferFlags;
  568. pInternalBuffer->Flags |= UC_RESPONSE_BUFFER_FLAG_NOT_MERGEABLE;
  569. //
  570. // Copy old HTTP_RESPONSE to new buffer's HTTP_RESPONSE.
  571. //
  572. pTmpHead = pBufferHead = (PUCHAR)(pInternalBuffer + 1);
  573. pTmpTail = pBufferTail = (PUCHAR)(pInternalBuffer) + BytesToAllocate;
  574. //
  575. // If we are using App's buffer, the InternalResponse must be used
  576. // while copying. Otherwise we use the original buffer's Response
  577. // strucuture. In any case, the CurrentBuffer.pResponse is already
  578. // init'ed to point to "the right" place.
  579. //
  580. ASSERT(pRequest->CurrentBuffer.pResponse != NULL);
  581. UcpCopyHttpResponseHeaders(&pInternalBuffer->HttpResponse,
  582. pRequest->CurrentBuffer.pResponse,
  583. &pBufferHead,
  584. &pBufferTail);
  585. ASSERT(pTmpHead <= pBufferHead);
  586. ASSERT(pTmpTail >= pBufferTail);
  587. ASSERT(pBufferHead <= pBufferTail);
  588. //
  589. // Set up the current buffer structure...
  590. //
  591. //
  592. // BytesAllocated is sizeof(HTTP_RESPONSE) + Data buffer length
  593. // It is used to determine how much space is needed to copy
  594. // this parsed response buffer.
  595. //
  596. pRequest->CurrentBuffer.BytesAllocated = BytesToAllocate -
  597. (sizeof(UC_RESPONSE_BUFFER) - sizeof(HTTP_RESPONSE));
  598. //
  599. // Update bytes allocated
  600. //
  601. pRequest->CurrentBuffer.BytesAvailable =
  602. pRequest->CurrentBuffer.BytesAllocated - sizeof(HTTP_RESPONSE)
  603. - (ULONG)(pBufferHead - pTmpHead)
  604. - (ULONG)(pTmpTail - pBufferTail);
  605. pRequest->CurrentBuffer.pResponse = &pInternalBuffer->HttpResponse;
  606. pRequest->CurrentBuffer.pOutBufferHead = pBufferHead;
  607. pRequest->CurrentBuffer.pOutBufferTail = pBufferTail;
  608. if (pRequest->CurrentBuffer.pCurrentBuffer)
  609. {
  610. //
  611. // Old buffer was a driver allocated buffer. Free it now.
  612. //
  613. PLIST_ENTRY pEntry;
  614. PUC_RESPONSE_BUFFER pOldResponseBuffer;
  615. //
  616. // Remove old buffer and insert new one.
  617. //
  618. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  619. pOldResponseBuffer = pRequest->CurrentBuffer.pCurrentBuffer;
  620. pEntry = RemoveHeadList(&pRequest->pBufferList);
  621. ASSERT(pEntry == &pRequest->CurrentBuffer.pCurrentBuffer->Linkage);
  622. InsertHeadList(&pRequest->pBufferList, &pInternalBuffer->Linkage);
  623. pRequest->CurrentBuffer.pCurrentBuffer = pInternalBuffer;
  624. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  625. UL_FREE_POOL_WITH_QUOTA(pOldResponseBuffer,
  626. UC_RESPONSE_APP_BUFFER_POOL_TAG,
  627. NonPagedPool,
  628. pOldResponseBuffer->BytesAllocated,
  629. pConnection->pServerInfo->pProcess);
  630. }
  631. else
  632. {
  633. //
  634. // App's buffer...complete App's IRP
  635. //
  636. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  637. //
  638. // Set the current buffer pointer.
  639. //
  640. pRequest->CurrentBuffer.pCurrentBuffer = pInternalBuffer;
  641. //
  642. // Insert the buffer in the list.
  643. //
  644. ASSERT(IsListEmpty(&pRequest->pBufferList));
  645. InsertHeadList(&pRequest->pBufferList, &pInternalBuffer->Linkage);
  646. //
  647. // Reference the request for the buffer just added.
  648. //
  649. UC_REFERENCE_REQUEST(pRequest);
  650. if(pRequest->CurrentBuffer.pResponse &&
  651. !((pRequest->ResponseStatusCode == 401 ||
  652. pRequest->ResponseStatusCode == 407) &&
  653. pRequest->Renegotiate == TRUE &&
  654. pRequest->DontFreeMdls == TRUE &&
  655. pRequest->RequestStatus == STATUS_SUCCESS
  656. )
  657. && pRequest->RequestState == UcRequestStateSendCompletePartialData
  658. )
  659. {
  660. //
  661. // Complete App's IRP with error
  662. //
  663. pIrp = UcPrepareRequestIrp(pRequest, STATUS_BUFFER_TOO_SMALL);
  664. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  665. if(pIrp)
  666. {
  667. pIrp->IoStatus.Information = BytesToAllocate;
  668. UlCompleteRequest(pIrp, 0);
  669. }
  670. }
  671. else
  672. {
  673. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  674. }
  675. }
  676. return STATUS_SUCCESS;
  677. }
  678. /***************************************************************************++
  679. Routine Description:
  680. This routine is used by the HTTP response parser to get buffer space to
  681. hold the parsed response.
  682. Arguments:
  683. pRequest - The internal HTTP request.
  684. BytesIndicated - The number of bytes indicated by TDI. We will buffer for
  685. at least this amount
  686. Return Value:
  687. NTSTATUS - Completion status.
  688. --***************************************************************************/
  689. NTSTATUS
  690. UcpGetResponseBuffer(
  691. IN PUC_HTTP_REQUEST pRequest,
  692. IN ULONG BytesIndicated,
  693. IN ULONG ResponseBufferFlags
  694. )
  695. {
  696. PUC_RESPONSE_BUFFER pInternalBuffer;
  697. PUC_CLIENT_CONNECTION pConnection = pRequest->pConnection;
  698. ULONG BytesToAllocate;
  699. ULONG AlignLength;
  700. KIRQL OldIrql;
  701. PIRP pIrp;
  702. //
  703. // All the headers must go into one buffer. If the buffer ran out
  704. // of space when parsing headers, a buffer is allocated and old contents
  705. // are copied to the new buffer. If the old buffer came from App, the
  706. // App's request is failed with STATUS_BUFFER_TOO_SMALL.
  707. //
  708. switch(pRequest->ParseState)
  709. {
  710. case UcParseStatusLineVersion:
  711. case UcParseStatusLineStatusCode:
  712. //
  713. // If we are allocating buffer in this state, then the buffers should
  714. // not be mergeable.
  715. //
  716. ResponseBufferFlags |= UC_RESPONSE_BUFFER_FLAG_NOT_MERGEABLE;
  717. break;
  718. case UcParseStatusLineReasonPhrase:
  719. case UcParseHeaders:
  720. //
  721. // If the app did not pass any buffers and this the first time
  722. // buffers are allocated for this response, goto the normal path.
  723. //
  724. if (pRequest->CurrentBuffer.BytesAllocated == 0)
  725. {
  726. break;
  727. }
  728. return UcpExpandResponseBuffer(pRequest,
  729. BytesIndicated,
  730. ResponseBufferFlags);
  731. default:
  732. break;
  733. }
  734. //
  735. // If we are in this routine, we have run out of buffer space. This
  736. // allows us to complete the app's IRP
  737. //
  738. if(!pRequest->CurrentBuffer.pCurrentBuffer)
  739. {
  740. if(pRequest->CurrentBuffer.pResponse &&
  741. !((pRequest->ResponseStatusCode == 401 ||
  742. pRequest->ResponseStatusCode == 407) &&
  743. pRequest->Renegotiate == TRUE &&
  744. pRequest->DontFreeMdls == TRUE &&
  745. pRequest->RequestStatus == STATUS_SUCCESS
  746. )
  747. )
  748. {
  749. pRequest->CurrentBuffer.pResponse->Flags |=
  750. HTTP_RESPONSE_FLAG_MORE_DATA;
  751. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  752. pRequest->RequestIRPBytesWritten =
  753. pRequest->CurrentBuffer.BytesAllocated -
  754. pRequest->CurrentBuffer.BytesAvailable;
  755. if(pRequest->RequestState ==
  756. UcRequestStateSendCompletePartialData)
  757. {
  758. //
  759. // We have been called in the send complete and we own
  760. // the IRP completion.
  761. //
  762. pIrp = UcPrepareRequestIrp(pRequest, STATUS_SUCCESS);
  763. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  764. if(pIrp)
  765. {
  766. UlCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  767. }
  768. }
  769. else
  770. {
  771. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  772. }
  773. }
  774. else
  775. {
  776. // App did not post any buffers, this IRP should have been
  777. // completed by the SendComplete handler.
  778. }
  779. }
  780. else
  781. {
  782. UlAcquireSpinLock(&pRequest->pConnection->SpinLock, &OldIrql);
  783. pRequest->CurrentBuffer.pCurrentBuffer->Flags |=
  784. UC_RESPONSE_BUFFER_FLAG_READY;
  785. pRequest->CurrentBuffer.pCurrentBuffer->BytesWritten =
  786. pRequest->CurrentBuffer.BytesAllocated -
  787. pRequest->CurrentBuffer.BytesAvailable;
  788. pRequest->CurrentBuffer.pResponse->Flags |=
  789. HTTP_RESPONSE_FLAG_MORE_DATA;
  790. //
  791. // Complete App's receive response Irp, if any.
  792. //
  793. UcpCompleteReceiveResponseIrp(pRequest, OldIrql);
  794. }
  795. //
  796. // UC_BUGBUG (PERF): want to use fixed size pools ?
  797. //
  798. //
  799. // TDI has indicated BytesIndicated bytes of data. We have to allocate
  800. // a buffer space for holding all of this data. Now, some of these might
  801. // be unknown headers or entity bodies. Since we parse unknown headers
  802. // and entity bodies as variable length arrays, we need some array space.
  803. // Since we have not parsed these unknown headers or entity bodies as yet,
  804. // we have to make a guess on the count of these and hope that we allocate
  805. // sufficient space. If our guess does not work, we'll land up calling
  806. // this routine again.
  807. //
  808. AlignLength = ALIGN_UP(BytesIndicated, PVOID);
  809. BytesToAllocate = AlignLength +
  810. sizeof(UC_RESPONSE_BUFFER) +
  811. UC_RESPONSE_EXTRA_BUFFER;
  812. pInternalBuffer = (PUC_RESPONSE_BUFFER)
  813. UL_ALLOCATE_POOL_WITH_QUOTA(
  814. NonPagedPool,
  815. BytesToAllocate,
  816. UC_RESPONSE_APP_BUFFER_POOL_TAG,
  817. pRequest->pServerInfo->pProcess
  818. );
  819. if(!pInternalBuffer)
  820. {
  821. UlTrace(PARSER,
  822. ("[UcpGetResponseBuffer]: Could not allocate memory for "
  823. "buffering \n"));
  824. return STATUS_INSUFFICIENT_RESOURCES;
  825. }
  826. RtlZeroMemory(pInternalBuffer, BytesToAllocate);
  827. //
  828. // Set up the internal request structure so that we have nice pointers.
  829. //
  830. pInternalBuffer->Signature = UC_RESPONSE_BUFFER_SIGNATURE;
  831. pInternalBuffer->BytesAllocated = BytesToAllocate;
  832. pInternalBuffer->Flags |= ResponseBufferFlags;
  833. pRequest->CurrentBuffer.BytesAllocated = AlignLength +
  834. UC_RESPONSE_EXTRA_BUFFER +
  835. sizeof(HTTP_RESPONSE);
  836. pRequest->CurrentBuffer.BytesAvailable =
  837. pRequest->CurrentBuffer.BytesAllocated - sizeof(HTTP_RESPONSE);
  838. pRequest->CurrentBuffer.pResponse = &pInternalBuffer->HttpResponse;
  839. pRequest->CurrentBuffer.pOutBufferHead =
  840. (PUCHAR) ((PUCHAR)pInternalBuffer + sizeof(UC_RESPONSE_BUFFER));
  841. pRequest->CurrentBuffer.pOutBufferTail =
  842. pRequest->CurrentBuffer.pOutBufferHead +
  843. AlignLength +
  844. UC_RESPONSE_EXTRA_BUFFER;
  845. pRequest->CurrentBuffer.pCurrentBuffer = pInternalBuffer;
  846. //
  847. // depending on where we are, setup the response pointers.
  848. //
  849. switch(pRequest->ParseState)
  850. {
  851. case UcParseEntityBody:
  852. case UcParseEntityBodyMultipartFinal:
  853. pRequest->CurrentBuffer.pResponse->pEntityChunks =
  854. (PHTTP_DATA_CHUNK)pRequest->CurrentBuffer.pOutBufferHead;
  855. break;
  856. case UcParseHeaders:
  857. case UcParseEntityBodyMultipartInit:
  858. case UcParseEntityBodyMultipartHeaders:
  859. pRequest->CurrentBuffer.pResponse->Headers.pUnknownHeaders =
  860. (PHTTP_UNKNOWN_HEADER) pRequest->CurrentBuffer.pOutBufferHead;
  861. break;
  862. default:
  863. break;
  864. }
  865. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  866. InsertTailList(
  867. &pRequest->pBufferList,
  868. &pInternalBuffer->Linkage
  869. );
  870. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  871. //
  872. // Take a ref on the request for this buffer
  873. //
  874. UC_REFERENCE_REQUEST(pRequest);
  875. return STATUS_SUCCESS;
  876. }
  877. /***************************************************************************++
  878. Routine Description:
  879. This routine is used by the HTTP response parser to merge a TDI indication
  880. with a previously buffered one.
  881. There could be cases when a TDI indication does not carry the entire
  882. data required to parse the HTTP response. For e.g. if we were parsing
  883. headers and the TDI indication ended with "Accept-", we would not know
  884. which header to parse the indication to.
  885. In such cases, we buffer the un-parsed portion of the response (in this
  886. case it would be "Accept-"), and merge the subsequent indication from TDI
  887. with the buffered indication, and process it as one chunk.
  888. Now, in order to minimize the buffering overhead, we don't merge all of the
  889. new indication with the old one. We just assume that the data can be parsed
  890. using the next 256 bytes, and copy that amount into the prior indication.
  891. If this was not sufficient, we'll just copy more data.
  892. We'll then treat these as two (or one) seperate indications.
  893. Arguments:
  894. pConnection - A pointer to UC_CLIENT_CONNECTION
  895. pIndication - A pointer to the (new) TDI indication.
  896. BytesIndicated - The number of bytes in the new indication.
  897. Indication - An output array that carries the seperated indications
  898. IndicationLength - An output array that stores the length of the
  899. indications.
  900. IndicationCount - The # of seperated indications.
  901. Return Value:
  902. NTSTATUS - Completion status.
  903. --***************************************************************************/
  904. VOID
  905. UcpMergeIndications(
  906. IN PUC_CLIENT_CONNECTION pConnection,
  907. IN PUCHAR pIndication,
  908. IN ULONG BytesIndicated,
  909. OUT PUCHAR Indication[2],
  910. OUT ULONG IndicationLength[2],
  911. OUT PULONG IndicationCount
  912. )
  913. {
  914. PUCHAR pOriginalIndication;
  915. ULONG BytesAvailable;
  916. //
  917. // It's okay to chain this off the connection - this is not a per-request
  918. // thing.
  919. //
  920. if(pConnection->MergeIndication.pBuffer)
  921. {
  922. //
  923. // Yes - there was a portion of a prior indication that we did not
  924. // consume. We'll just assume that the next
  925. //
  926. pOriginalIndication = pConnection->MergeIndication.pBuffer +
  927. pConnection->MergeIndication.BytesWritten;
  928. BytesAvailable = pConnection->MergeIndication.BytesAllocated -
  929. pConnection->MergeIndication.BytesWritten;
  930. if(BytesIndicated <= BytesAvailable)
  931. {
  932. // the second indication completly fits into our merge buffer.
  933. // we'll just merge all of this and treat as one indication.
  934. RtlCopyMemory(pOriginalIndication,
  935. pIndication,
  936. BytesIndicated);
  937. pConnection->MergeIndication.BytesWritten += BytesIndicated;
  938. *IndicationCount = 1;
  939. Indication[0] = pConnection->MergeIndication.pBuffer;
  940. IndicationLength[0] = pConnection->MergeIndication.BytesWritten;
  941. }
  942. else
  943. {
  944. // Fill up the Merge buffer completly.
  945. RtlCopyMemory(pOriginalIndication,
  946. pIndication,
  947. BytesAvailable);
  948. pConnection->MergeIndication.BytesWritten += BytesAvailable;
  949. pIndication += BytesAvailable;
  950. BytesIndicated -= BytesAvailable;
  951. //
  952. // We need to process 2 buffers.
  953. //
  954. *IndicationCount = 2;
  955. Indication[0] = pConnection->MergeIndication.pBuffer;
  956. IndicationLength[0] = pConnection->MergeIndication.BytesWritten;
  957. Indication[1] = pIndication;
  958. IndicationLength[1] = BytesIndicated;
  959. }
  960. }
  961. else
  962. {
  963. //
  964. // No original buffer, let's just process the new indication.
  965. //
  966. *IndicationCount = 1;
  967. Indication[0] = pIndication;
  968. IndicationLength[0] = BytesIndicated;
  969. }
  970. }
  971. /***************************************************************************++
  972. Routine Description:
  973. This is the core HTTP response protocol parsing engine. It takes a stream of
  974. bytes and parses them as a HTTP response.
  975. Arguments:
  976. pRequest - The Internal HTTP request structure.
  977. pIndicatedBuffer - The current Indication
  978. BytesIndicated - Size of the current Indication.
  979. BytesTaken - An output parameter that indicates the # of bytes that
  980. got consumed by the parser. Note that even when this
  981. routine returns an error code, it could have consumed
  982. some amount of data.
  983. For e.g. if we got something like
  984. "HTTP/1.1 200 OK .... CRLF Accept-", we'll consume all
  985. data till the "Accept-".
  986. Return Value:
  987. NTSTATUS - Completion status.
  988. STATUS_MORE_PROCESSING_REQUIRED : The Indication was not sufficient to
  989. parse the response. This happens when
  990. the indication ends inbetween a header
  991. boundary. In such cases, the caller has
  992. to buffer the data and call this routine
  993. when it gets more data.
  994. STATUS_INSUFFICIENT_RESOURCES : The parser ran out of output buffer.
  995. When this happens, the parser has to get
  996. more buffer and resume the parsing.
  997. STATUS_SUCCESS : This request got parsed successfully.
  998. STATUS_INVALID_NETWORK_RESPONSE : Illegal HTTP response.
  999. --***************************************************************************/
  1000. NTSTATUS
  1001. UcpParseHttpResponse(
  1002. PUC_HTTP_REQUEST pRequest,
  1003. PUCHAR pIndicatedBuffer,
  1004. ULONG BytesIndicated,
  1005. PULONG BytesTaken
  1006. )
  1007. {
  1008. PUCHAR pStartReason, pStart;
  1009. PHTTP_RESPONSE pResponse;
  1010. ULONG i;
  1011. NTSTATUS Status;
  1012. ULONG ResponseRangeLength, HeaderBytesTaken;
  1013. PCHAR pEnd;
  1014. ULONG AlignLength;
  1015. BOOLEAN bFoundLWS, bEnd;
  1016. BOOLEAN bIgnoreParsing;
  1017. PUCHAR pFoldingBuffer = NULL;
  1018. ULONG EntityBytesTaken;
  1019. UC_DATACHUNK_RETURN DataChunkStatus;
  1020. USHORT OldMinorVersion;
  1021. HeaderBytesTaken = 0;
  1022. *BytesTaken = 0;
  1023. pResponse = pRequest->CurrentBuffer.pResponse;
  1024. bIgnoreParsing = (BOOLEAN)(pRequest->RequestFlags.ProxySslConnect != 0);
  1025. if(!pResponse)
  1026. {
  1027. return STATUS_INSUFFICIENT_RESOURCES;
  1028. }
  1029. while(BytesIndicated > 0)
  1030. {
  1031. switch(pRequest->ParseState)
  1032. {
  1033. case UcParseStatusLineVersion:
  1034. //
  1035. // Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
  1036. //
  1037. pStart = pIndicatedBuffer;
  1038. //
  1039. // Skip LWS
  1040. //
  1041. while(BytesIndicated && IS_HTTP_LWS(*pIndicatedBuffer))
  1042. {
  1043. pIndicatedBuffer ++;
  1044. BytesIndicated --;
  1045. }
  1046. //
  1047. // Do we have enough buffer to strcmp the version ?
  1048. //
  1049. if(BytesIndicated < MIN_VERSION_SIZE)
  1050. {
  1051. return STATUS_MORE_PROCESSING_REQUIRED;
  1052. }
  1053. ASSERT(VERSION_OTHER_SIZE <= MIN_VERSION_SIZE);
  1054. if(strncmp((const char *)pIndicatedBuffer,
  1055. HTTP_VERSION_OTHER,
  1056. VERSION_OTHER_SIZE) == 0)
  1057. {
  1058. pIndicatedBuffer = pIndicatedBuffer + VERSION_OTHER_SIZE;
  1059. BytesIndicated -= VERSION_OTHER_SIZE;
  1060. //
  1061. // Parse the Major Version number. We'll only accept a major
  1062. // version of 1.
  1063. //
  1064. pResponse->Version.MajorVersion = 0;
  1065. while(BytesIndicated > 0 && IS_HTTP_DIGIT(*pIndicatedBuffer))
  1066. {
  1067. pResponse->Version.MajorVersion =
  1068. (pResponse->Version.MajorVersion * 10) +
  1069. *pIndicatedBuffer - '0';
  1070. pIndicatedBuffer ++;
  1071. BytesIndicated --;
  1072. //
  1073. // Check for overflow.
  1074. //
  1075. if(pResponse->Version.MajorVersion > 1)
  1076. {
  1077. UlTrace(PARSER,
  1078. ("[UcpParseHttpResponse]:Invalid HTTP "
  1079. "version \n"));
  1080. return STATUS_INVALID_NETWORK_RESPONSE;
  1081. }
  1082. }
  1083. if(0 == BytesIndicated)
  1084. {
  1085. return STATUS_MORE_PROCESSING_REQUIRED;
  1086. }
  1087. if(*pIndicatedBuffer != '.' ||
  1088. pResponse->Version.MajorVersion != 1)
  1089. {
  1090. //
  1091. // INVALID HTTP version!!
  1092. //
  1093. UlTrace(PARSER,
  1094. ("[UcpParseHttpResponse]:Invalid HTTP version \n"));
  1095. return STATUS_INVALID_NETWORK_RESPONSE;
  1096. }
  1097. //
  1098. // Ignore the '.'
  1099. //
  1100. pIndicatedBuffer ++;
  1101. BytesIndicated --;
  1102. //
  1103. // Parse the Minor Version number. We'll accept anything for
  1104. // the minor version number as long as it's a USHORT (to be
  1105. // protocol compliant)
  1106. //
  1107. pResponse->Version.MinorVersion = 0;
  1108. OldMinorVersion = 0;
  1109. while(BytesIndicated > 0 && IS_HTTP_DIGIT(*pIndicatedBuffer))
  1110. {
  1111. OldMinorVersion = pResponse->Version.MinorVersion;
  1112. pResponse->Version.MinorVersion =
  1113. (pResponse->Version.MinorVersion * 10) +
  1114. *pIndicatedBuffer - '0';
  1115. pIndicatedBuffer ++;
  1116. BytesIndicated --;
  1117. //
  1118. // Check for overflow.
  1119. //
  1120. if(pResponse->Version.MinorVersion < OldMinorVersion)
  1121. {
  1122. UlTrace(PARSER,
  1123. ("[UcpParseHttpResponse]:Invalid HTTP "
  1124. "version \n"));
  1125. return STATUS_INVALID_NETWORK_RESPONSE;
  1126. }
  1127. }
  1128. if(0 == BytesIndicated)
  1129. {
  1130. return STATUS_MORE_PROCESSING_REQUIRED;
  1131. }
  1132. ASSERT(pResponse->Version.MajorVersion == 1 );
  1133. if(
  1134. pResponse->Version.MinorVersion == 0
  1135. )
  1136. {
  1137. // By default, we have to close the connection for 1.0
  1138. // requests.
  1139. pRequest->ResponseVersion11 = FALSE;
  1140. pRequest->ResponseConnectionClose = TRUE;
  1141. }
  1142. else
  1143. {
  1144. PUC_CLIENT_CONNECTION pConnection;
  1145. pRequest->ResponseVersion11 = TRUE;
  1146. pRequest->ResponseConnectionClose = FALSE;
  1147. //
  1148. // Also update the version number on the COMMON
  1149. // SERVINFO, so that future requests to this server use
  1150. // the proper version.
  1151. //
  1152. pConnection = pRequest->pConnection;
  1153. pConnection->pServerInfo->pNextHopInfo->Version11 = TRUE;
  1154. }
  1155. pRequest->ParseState = UcParseStatusLineStatusCode;
  1156. *BytesTaken += DIFF(pIndicatedBuffer - pStart);
  1157. }
  1158. else
  1159. {
  1160. UlTrace(PARSER,
  1161. ("[UcpParseHttpResponse]: Invalid HTTP version \n"));
  1162. return STATUS_INVALID_NETWORK_RESPONSE;
  1163. }
  1164. //
  1165. // FALLTHROUGH
  1166. //
  1167. case UcParseStatusLineStatusCode:
  1168. ASSERT(pRequest->ParseState == UcParseStatusLineStatusCode);
  1169. pStart = pIndicatedBuffer;
  1170. //
  1171. // skip LWS
  1172. //
  1173. bFoundLWS = FALSE;
  1174. while(BytesIndicated && IS_HTTP_LWS(*pIndicatedBuffer))
  1175. {
  1176. bFoundLWS = TRUE;
  1177. pIndicatedBuffer ++;
  1178. BytesIndicated --;
  1179. }
  1180. //
  1181. // NOTE: Order of the following two if conditions is important
  1182. // We don't want to fail this response if we got here when
  1183. // BytesIndicated was 0 in the first place.
  1184. //
  1185. if(BytesIndicated < STATUS_CODE_LENGTH)
  1186. {
  1187. return STATUS_MORE_PROCESSING_REQUIRED;
  1188. }
  1189. if(!bFoundLWS)
  1190. {
  1191. UlTrace(PARSER,
  1192. ("[UcpParseHttpResponse]: No LWS between reason & "
  1193. "status code \n"));
  1194. return STATUS_INVALID_NETWORK_RESPONSE;
  1195. }
  1196. pResponse->StatusCode = 0;
  1197. for(i = 0; i < STATUS_CODE_LENGTH; i++)
  1198. {
  1199. //
  1200. // The status code has to be a 3 digit string
  1201. //
  1202. if(!IS_HTTP_DIGIT(*pIndicatedBuffer))
  1203. {
  1204. UlTrace(PARSER,
  1205. ("[UcpParseHttpResponse]: Invalid status code \n"));
  1206. return STATUS_INVALID_NETWORK_RESPONSE;
  1207. }
  1208. pResponse->StatusCode = (pResponse->StatusCode * 10) +
  1209. *pIndicatedBuffer - '0';
  1210. pIndicatedBuffer ++;
  1211. BytesIndicated --;
  1212. }
  1213. pRequest->ResponseStatusCode = pResponse->StatusCode;
  1214. pRequest->ParseState = UcParseStatusLineReasonPhrase;
  1215. if(pRequest->ResponseStatusCode >= 100 &&
  1216. pRequest->ResponseStatusCode <= 199 &&
  1217. pRequest->pServerInfo->IgnoreContinues)
  1218. {
  1219. bIgnoreParsing = TRUE;
  1220. }
  1221. *BytesTaken += DIFF(pIndicatedBuffer - pStart);
  1222. //
  1223. // FALLTHROUGH
  1224. //
  1225. case UcParseStatusLineReasonPhrase:
  1226. ASSERT(pRequest->ParseState == UcParseStatusLineReasonPhrase);
  1227. pStart = pIndicatedBuffer;
  1228. //
  1229. // Make sure we have bytes to look for a LWS. Make sure that it is
  1230. // indeed a LWS.
  1231. //
  1232. bFoundLWS = FALSE;
  1233. while(BytesIndicated && IS_HTTP_LWS(*pIndicatedBuffer))
  1234. {
  1235. bFoundLWS = TRUE;
  1236. pIndicatedBuffer ++;
  1237. BytesIndicated --;
  1238. }
  1239. //
  1240. // NOTE: Order of the following two if conditions is important
  1241. // We don't want to fail this response if we got here when
  1242. // BytesIndicated was 0 in the first place.
  1243. //
  1244. if(BytesIndicated == 0)
  1245. {
  1246. return STATUS_MORE_PROCESSING_REQUIRED;
  1247. }
  1248. if(!bFoundLWS)
  1249. {
  1250. UlTrace(PARSER,
  1251. ("[UcpParseHttpResponse]: No LWS between reason & "
  1252. "status code \n"));
  1253. return STATUS_INVALID_NETWORK_RESPONSE;
  1254. }
  1255. //
  1256. // Look for a CRLF
  1257. //
  1258. pStartReason = pIndicatedBuffer;
  1259. while(BytesIndicated >= CRLF_SIZE)
  1260. {
  1261. if (*(UNALIGNED64 USHORT *)pIndicatedBuffer == CRLF ||
  1262. *(UNALIGNED64 USHORT *)pIndicatedBuffer == LFLF)
  1263. {
  1264. break;
  1265. }
  1266. //
  1267. // Advance to the next character.
  1268. //
  1269. pIndicatedBuffer ++;
  1270. BytesIndicated --;
  1271. }
  1272. if(BytesIndicated < CRLF_SIZE)
  1273. {
  1274. return STATUS_MORE_PROCESSING_REQUIRED;
  1275. }
  1276. //
  1277. // We've reached end of reason string, consume the CRLF.
  1278. //
  1279. pIndicatedBuffer += CRLF_SIZE;
  1280. BytesIndicated -= CRLF_SIZE;
  1281. if(!bIgnoreParsing)
  1282. {
  1283. //
  1284. // Set the reason string pointer and copy out the reason
  1285. // string.
  1286. //
  1287. pResponse->pReason=
  1288. (PSTR)pRequest->CurrentBuffer.pOutBufferHead;
  1289. pResponse->ReasonLength
  1290. = DIFF_USHORT(pIndicatedBuffer - pStartReason) - CRLF_SIZE;
  1291. AlignLength = ALIGN_UP(pResponse->ReasonLength, PVOID);
  1292. if(pRequest->CurrentBuffer.BytesAvailable >= AlignLength)
  1293. {
  1294. RtlCopyMemory((PSTR) pResponse->pReason,
  1295. pStartReason,
  1296. pResponse->ReasonLength);
  1297. pRequest->CurrentBuffer.pOutBufferHead += AlignLength;
  1298. pRequest->CurrentBuffer.BytesAvailable -= AlignLength;
  1299. }
  1300. else
  1301. {
  1302. pResponse->pReason = NULL;
  1303. pResponse->ReasonLength = 0;
  1304. return STATUS_INSUFFICIENT_RESOURCES;
  1305. }
  1306. }
  1307. // The head pointer is now going to be used for the unknown header
  1308. // array. Let's set it.
  1309. //
  1310. pResponse->Headers.pUnknownHeaders = (PHTTP_UNKNOWN_HEADER)
  1311. pRequest->CurrentBuffer.pOutBufferHead;
  1312. *BytesTaken += DIFF(pIndicatedBuffer - pStart);
  1313. pRequest->ParseState = UcParseHeaders;
  1314. //
  1315. // FALLTHROUGH
  1316. //
  1317. ASSERT(pRequest->ParseState == UcParseHeaders);
  1318. case UcParseHeaders:
  1319. case UcParseTrailers:
  1320. case UcParseEntityBodyMultipartHeaders:
  1321. pStart = pIndicatedBuffer;
  1322. while(BytesIndicated >= CRLF_SIZE)
  1323. {
  1324. //
  1325. // If this is an empty header, we are done.
  1326. //
  1327. if (*(UNALIGNED64 USHORT *)pIndicatedBuffer == CRLF ||
  1328. *(UNALIGNED64 USHORT *)pIndicatedBuffer == LFLF)
  1329. {
  1330. break;
  1331. }
  1332. //
  1333. // Parse the headers.
  1334. //
  1335. if(bIgnoreParsing)
  1336. {
  1337. ULONG HeaderNameLength;
  1338. Status = UcFindHeaderNameEnd(
  1339. pIndicatedBuffer,
  1340. BytesIndicated,
  1341. &HeaderNameLength
  1342. );
  1343. if(!NT_SUCCESS(Status))
  1344. {
  1345. return Status;
  1346. }
  1347. ASSERT(BytesIndicated - HeaderNameLength
  1348. < ANSI_STRING_MAX_CHAR_LEN);
  1349. Status = UcFindHeaderValueEnd(
  1350. pIndicatedBuffer + HeaderNameLength,
  1351. (USHORT) (BytesIndicated - HeaderNameLength),
  1352. &pFoldingBuffer,
  1353. &HeaderBytesTaken
  1354. );
  1355. if(!NT_SUCCESS(Status))
  1356. {
  1357. return Status;
  1358. };
  1359. ASSERT(HeaderBytesTaken != 0);
  1360. // No need to check for NT_STATUS here. We are ignoring
  1361. // headers anyway.
  1362. if(pFoldingBuffer)
  1363. {
  1364. UL_FREE_POOL(
  1365. pFoldingBuffer,
  1366. UC_HEADER_FOLDING_POOL_TAG
  1367. );
  1368. }
  1369. HeaderBytesTaken += HeaderNameLength;
  1370. }
  1371. else
  1372. {
  1373. Status = UcParseHeader(pRequest,
  1374. pIndicatedBuffer,
  1375. BytesIndicated,
  1376. &HeaderBytesTaken);
  1377. }
  1378. if(!NT_SUCCESS(Status))
  1379. {
  1380. return Status;
  1381. }
  1382. else
  1383. {
  1384. ASSERT(HeaderBytesTaken != 0);
  1385. pIndicatedBuffer += HeaderBytesTaken;
  1386. BytesIndicated -= HeaderBytesTaken;
  1387. *BytesTaken += HeaderBytesTaken;
  1388. }
  1389. }
  1390. if(BytesIndicated >= CRLF_SIZE)
  1391. {
  1392. //
  1393. // We have reached the end of the headers.
  1394. //
  1395. pIndicatedBuffer += CRLF_SIZE;
  1396. BytesIndicated -= CRLF_SIZE;
  1397. *BytesTaken += CRLF_SIZE;
  1398. //
  1399. // If we were parsing headers, we have to parse entity bodies.
  1400. // if we were parsing trailers, we are done!
  1401. //
  1402. if(pRequest->ParseState == UcParseHeaders)
  1403. {
  1404. //
  1405. // See if it is valid for this response to include a
  1406. // message body. All 1xx, 204 and 304 responses should not
  1407. // have a message body.
  1408. //
  1409. // For 1XX responses, we need to re-set the ParseState to
  1410. // Init, so that we parse the subsequent response also.
  1411. //
  1412. if((pResponse->StatusCode >= 100 &&
  1413. pResponse->StatusCode <= 199))
  1414. {
  1415. pRequest->ParseState = UcParseStatusLineVersion;
  1416. if(!bIgnoreParsing)
  1417. {
  1418. return STATUS_INSUFFICIENT_RESOURCES;
  1419. }
  1420. else
  1421. {
  1422. continue;
  1423. }
  1424. }
  1425. if((pResponse->StatusCode == 204) ||
  1426. (pResponse->StatusCode == 304) ||
  1427. (pRequest->RequestFlags.NoResponseEntityBodies == TRUE)
  1428. )
  1429. {
  1430. //
  1431. // These responses cannot have a entity body. If a
  1432. // rogue server has passed an entity body, it will
  1433. // just be treated as the part of a subsequent
  1434. // indication
  1435. //
  1436. pRequest->ParseState = UcParseDone;
  1437. return STATUS_SUCCESS;
  1438. }
  1439. //
  1440. // Set up the pointers for the entity body.
  1441. //
  1442. pResponse->EntityChunkCount = 0;
  1443. pResponse->pEntityChunks = (PHTTP_DATA_CHUNK)
  1444. pRequest->CurrentBuffer.pOutBufferHead;
  1445. if(pResponse->StatusCode == 206 &&
  1446. pRequest->ResponseMultipartByteranges)
  1447. {
  1448. if(pRequest->ResponseEncodingChunked)
  1449. {
  1450. // UC_BUGBUG (WORKITEM)
  1451. // Ouch. We can't handle this right now.
  1452. // we have to first unchunk the entitities,
  1453. // and then decode the multipart response.
  1454. // for now, we'll fail this request.
  1455. UlTrace(PARSER,
  1456. ("[UcpParseHttpResponse]: "
  1457. "Multipart-chunked\n"));
  1458. return STATUS_INVALID_NETWORK_RESPONSE;
  1459. }
  1460. // multipart byterange
  1461. pRequest->ParseState = UcParseEntityBodyMultipartInit;
  1462. }
  1463. else
  1464. {
  1465. pRequest->ParseState = UcParseEntityBody;
  1466. }
  1467. }
  1468. else if(pRequest->ParseState == UcParseTrailers)
  1469. {
  1470. pRequest->ParseState = UcParseDone;
  1471. return STATUS_SUCCESS;
  1472. }
  1473. else
  1474. {
  1475. pResponse->EntityChunkCount = 0;
  1476. pResponse->pEntityChunks = (PHTTP_DATA_CHUNK)
  1477. pRequest->CurrentBuffer.pOutBufferHead;
  1478. pRequest->ParseState = UcParseEntityBodyMultipartFinal;
  1479. pRequest->MultipartRangeRemaining = 0;
  1480. }
  1481. }
  1482. else
  1483. {
  1484. return STATUS_MORE_PROCESSING_REQUIRED;
  1485. }
  1486. break;
  1487. case UcParseEntityBodyMultipartInit:
  1488. pStart = pIndicatedBuffer;
  1489. if(BytesIndicated >= pRequest->MultipartStringSeparatorLength)
  1490. {
  1491. pEnd = UxStrStr(
  1492. (const char *) pIndicatedBuffer,
  1493. (const char *) pRequest->pMultipartStringSeparator,
  1494. BytesIndicated
  1495. );
  1496. if(!pEnd)
  1497. {
  1498. return STATUS_MORE_PROCESSING_REQUIRED;
  1499. }
  1500. pIndicatedBuffer =
  1501. (PUCHAR) pEnd + pRequest->MultipartStringSeparatorLength;
  1502. BytesIndicated -= DIFF(pIndicatedBuffer - pStart);
  1503. if(BytesIndicated >= 2 &&
  1504. *pIndicatedBuffer == '-' && *(pIndicatedBuffer+1) == '-')
  1505. {
  1506. BytesIndicated -= 2;
  1507. pIndicatedBuffer += 2;
  1508. bEnd = TRUE;
  1509. }
  1510. else
  1511. {
  1512. bEnd = FALSE;
  1513. }
  1514. //
  1515. // skip any LWS.
  1516. //
  1517. while(BytesIndicated && IS_HTTP_LWS(*pIndicatedBuffer))
  1518. {
  1519. pIndicatedBuffer ++;
  1520. BytesIndicated --;
  1521. }
  1522. if(BytesIndicated >= 2)
  1523. {
  1524. if(*(UNALIGNED64 USHORT *)pIndicatedBuffer == CRLF ||
  1525. *(UNALIGNED64 USHORT *)pIndicatedBuffer == LFLF)
  1526. {
  1527. BytesIndicated -= CRLF_SIZE;
  1528. pIndicatedBuffer += CRLF_SIZE;
  1529. if(!bEnd)
  1530. {
  1531. // we are ready to parse the range. Since we always
  1532. // indicate Multipart in a new HTTP_RESPONSE
  1533. // structure, get more buffer.
  1534. Status = UcpGetResponseBuffer(
  1535. pRequest,
  1536. BytesIndicated,
  1537. UC_RESPONSE_BUFFER_FLAG_NOT_MERGEABLE);
  1538. if(!NT_SUCCESS(Status))
  1539. {
  1540. return Status;
  1541. }
  1542. pResponse = pRequest->CurrentBuffer.pResponse;
  1543. pRequest->ParseState =
  1544. UcParseEntityBodyMultipartHeaders;
  1545. }
  1546. else
  1547. {
  1548. if(BytesIndicated == 2)
  1549. {
  1550. if(*(UNALIGNED64 USHORT *)pIndicatedBuffer
  1551. == CRLF)
  1552. {
  1553. BytesIndicated -= CRLF_SIZE;
  1554. pIndicatedBuffer += CRLF_SIZE;
  1555. pRequest->ParseState = UcParseDone;
  1556. }
  1557. else
  1558. {
  1559. return STATUS_INVALID_NETWORK_RESPONSE;
  1560. }
  1561. }
  1562. else
  1563. {
  1564. return STATUS_MORE_PROCESSING_REQUIRED;
  1565. }
  1566. }
  1567. }
  1568. }
  1569. else
  1570. {
  1571. return STATUS_MORE_PROCESSING_REQUIRED;
  1572. }
  1573. }
  1574. else
  1575. {
  1576. return STATUS_MORE_PROCESSING_REQUIRED;
  1577. }
  1578. *BytesTaken += DIFF(pIndicatedBuffer - pStart);
  1579. break;
  1580. case UcParseEntityBodyMultipartFinal:
  1581. //
  1582. // We have parsed out the Content-Type & Content-Range of the
  1583. // Multipart encoding, we now proceed to carve out HTTP_DATA_CHUNKs
  1584. // for the data. We will keep searching the data till we hit a
  1585. // seperator.
  1586. //
  1587. if(pRequest->MultipartRangeRemaining != 0)
  1588. {
  1589. //
  1590. // We didn't consume part of an earlier range.
  1591. //
  1592. DataChunkStatus = UcpCopyEntityToDataChunk(
  1593. pResponse,
  1594. pRequest,
  1595. pRequest->MultipartRangeRemaining, // BytesToTake
  1596. BytesIndicated, // BytesIndicated
  1597. pIndicatedBuffer,
  1598. &EntityBytesTaken
  1599. );
  1600. *BytesTaken += EntityBytesTaken;
  1601. pRequest->MultipartRangeRemaining -= EntityBytesTaken;
  1602. if(UcDataChunkCopyAll == DataChunkStatus)
  1603. {
  1604. if(0 == pRequest->MultipartRangeRemaining)
  1605. {
  1606. // Done with this range, we consumed all of it.
  1607. pRequest->ParseState = UcParseEntityBodyMultipartInit;
  1608. pIndicatedBuffer += EntityBytesTaken;
  1609. BytesIndicated -= EntityBytesTaken;
  1610. break;
  1611. }
  1612. else
  1613. {
  1614. // We consumed all, but there's more data remaining.
  1615. return STATUS_MORE_PROCESSING_REQUIRED;
  1616. }
  1617. }
  1618. else
  1619. {
  1620. // We consumed partial, need more buffer
  1621. return STATUS_INSUFFICIENT_RESOURCES;
  1622. }
  1623. }
  1624. else if(BytesIndicated >= pRequest->MultipartStringSeparatorLength)
  1625. {
  1626. pEnd = UxStrStr(
  1627. (const char *) pIndicatedBuffer,
  1628. (const char *) pRequest->pMultipartStringSeparator,
  1629. BytesIndicated
  1630. );
  1631. if(!pEnd)
  1632. {
  1633. // If we haven't reached the end, we can't blindly carve
  1634. // out a data chunk with whatever we have! This is because
  1635. // we could have a case where the StringSeperator is
  1636. // spread across indications & we wouldn't want to treat
  1637. // the part of the string separator as entity!
  1638. // So, we'll carve out a data chunk for
  1639. // BytesIndicated - MultipartStringSeparatorLength. we are
  1640. // guaranteed that this is entity body.
  1641. ResponseRangeLength =
  1642. BytesIndicated - pRequest->MultipartStringSeparatorLength;
  1643. DataChunkStatus = UcpCopyEntityToDataChunk(
  1644. pResponse,
  1645. pRequest,
  1646. ResponseRangeLength, // BytesToTake
  1647. BytesIndicated, // BytesIndicated
  1648. pIndicatedBuffer,
  1649. &EntityBytesTaken
  1650. );
  1651. *BytesTaken += EntityBytesTaken;
  1652. if(UcDataChunkCopyAll == DataChunkStatus)
  1653. {
  1654. // Since we haven't yet seen the terminator, we have
  1655. // to return STATUS_MORE_PROCESSING_REQUIRED.
  1656. //
  1657. return STATUS_MORE_PROCESSING_REQUIRED;
  1658. }
  1659. else
  1660. {
  1661. // consumed partial, more buffer required
  1662. return STATUS_INSUFFICIENT_RESOURCES;
  1663. }
  1664. }
  1665. else
  1666. {
  1667. ResponseRangeLength = DIFF((PUCHAR)pEnd - pIndicatedBuffer);
  1668. ASSERT(ResponseRangeLength < BytesIndicated);
  1669. DataChunkStatus = UcpCopyEntityToDataChunk(
  1670. pResponse,
  1671. pRequest,
  1672. ResponseRangeLength, // BytesToTake
  1673. BytesIndicated, // BytesIndicated
  1674. pIndicatedBuffer,
  1675. &EntityBytesTaken
  1676. );
  1677. *BytesTaken += EntityBytesTaken;
  1678. if(UcDataChunkCopyAll == DataChunkStatus)
  1679. {
  1680. //
  1681. // Done with this range, we consumed all of it.
  1682. //
  1683. ASSERT(EntityBytesTaken == ResponseRangeLength);
  1684. pRequest->ParseState = UcParseEntityBodyMultipartInit;
  1685. // Update these fields, because we have to continue
  1686. // parsing.
  1687. pIndicatedBuffer += ResponseRangeLength;
  1688. BytesIndicated -= ResponseRangeLength;
  1689. break;
  1690. }
  1691. else
  1692. {
  1693. // this field has to be a ULONG, because we are
  1694. // gated by BytesIndicated. It doesn't have to be a
  1695. // ULONGLONG.
  1696. pRequest->MultipartRangeRemaining =
  1697. ResponseRangeLength - EntityBytesTaken;
  1698. return STATUS_INSUFFICIENT_RESOURCES;
  1699. }
  1700. }
  1701. }
  1702. else
  1703. {
  1704. return STATUS_MORE_PROCESSING_REQUIRED;
  1705. }
  1706. break;
  1707. case UcParseEntityBody:
  1708. if(pRequest->ResponseEncodingChunked)
  1709. {
  1710. //
  1711. // If there's a chunk that we've not fully consumed.
  1712. // The chunk-length of the current chunk is stored in
  1713. // ResponseContentLength.
  1714. //
  1715. if(pRequest->ResponseContentLength)
  1716. {
  1717. DataChunkStatus =
  1718. UcpCopyEntityToDataChunk(
  1719. pResponse,
  1720. pRequest,
  1721. (ULONG)pRequest->ResponseContentLength,
  1722. BytesIndicated,
  1723. pIndicatedBuffer,
  1724. &EntityBytesTaken
  1725. );
  1726. pRequest->ResponseContentLength -= EntityBytesTaken;
  1727. *BytesTaken += EntityBytesTaken;
  1728. if(UcDataChunkCopyAll == DataChunkStatus)
  1729. {
  1730. if(0 == pRequest->ResponseContentLength)
  1731. {
  1732. // We are done. Move onto the next chunk.
  1733. //
  1734. pIndicatedBuffer += EntityBytesTaken;
  1735. BytesIndicated -= EntityBytesTaken;
  1736. break;
  1737. }
  1738. else
  1739. {
  1740. ASSERT(BytesIndicated == EntityBytesTaken);
  1741. return STATUS_MORE_PROCESSING_REQUIRED;
  1742. }
  1743. }
  1744. else
  1745. {
  1746. return STATUS_INSUFFICIENT_RESOURCES;
  1747. }
  1748. }
  1749. else
  1750. {
  1751. ULONG ChunkBytesTaken;
  1752. Status = ParseChunkLength(
  1753. pRequest->ParsedFirstChunk,
  1754. pIndicatedBuffer,
  1755. BytesIndicated,
  1756. &ChunkBytesTaken,
  1757. &pRequest->ResponseContentLength
  1758. );
  1759. if(!NT_SUCCESS(Status))
  1760. {
  1761. return Status;
  1762. }
  1763. *BytesTaken += ChunkBytesTaken;
  1764. pIndicatedBuffer += ChunkBytesTaken;
  1765. BytesIndicated -= ChunkBytesTaken;
  1766. pRequest->ParsedFirstChunk = 1;
  1767. if(0 == pRequest->ResponseContentLength)
  1768. {
  1769. //
  1770. // We are done - Let's handle the trailers.
  1771. //
  1772. pRequest->ParseState = UcParseTrailers;
  1773. bIgnoreParsing = TRUE;
  1774. }
  1775. break;
  1776. }
  1777. }
  1778. else if(pRequest->ResponseContentLengthSpecified)
  1779. {
  1780. if(pRequest->ResponseContentLength == 0)
  1781. {
  1782. pRequest->ParseState = UcParseDone;
  1783. return STATUS_SUCCESS;
  1784. }
  1785. DataChunkStatus = UcpCopyEntityToDataChunk(
  1786. pResponse,
  1787. pRequest,
  1788. (ULONG) pRequest->ResponseContentLength,
  1789. BytesIndicated,
  1790. pIndicatedBuffer,
  1791. &EntityBytesTaken
  1792. );
  1793. *BytesTaken += EntityBytesTaken;
  1794. pRequest->ResponseContentLength -= EntityBytesTaken;
  1795. if(UcDataChunkCopyAll == DataChunkStatus)
  1796. {
  1797. if(0 == pRequest->ResponseContentLength)
  1798. {
  1799. //
  1800. // We've consumed everything.
  1801. //
  1802. pRequest->ParseState = UcParseDone;
  1803. return STATUS_SUCCESS;
  1804. }
  1805. else
  1806. {
  1807. return STATUS_MORE_PROCESSING_REQUIRED;
  1808. }
  1809. }
  1810. else
  1811. {
  1812. return STATUS_INSUFFICIENT_RESOURCES;
  1813. }
  1814. }
  1815. else
  1816. {
  1817. //
  1818. // Consume all of it. We will assume that this will end when
  1819. // we get called in the disconnect handler.
  1820. //
  1821. DataChunkStatus = UcpCopyEntityToDataChunk(
  1822. pResponse,
  1823. pRequest,
  1824. BytesIndicated,
  1825. BytesIndicated,
  1826. pIndicatedBuffer,
  1827. &EntityBytesTaken
  1828. );
  1829. *BytesTaken += EntityBytesTaken;
  1830. if(UcDataChunkCopyAll == DataChunkStatus)
  1831. {
  1832. return STATUS_MORE_PROCESSING_REQUIRED;
  1833. }
  1834. else
  1835. {
  1836. return STATUS_INSUFFICIENT_RESOURCES;
  1837. }
  1838. }
  1839. break;
  1840. case UcParseDone:
  1841. return STATUS_SUCCESS;
  1842. break;
  1843. default:
  1844. ASSERT(FALSE);
  1845. UlTrace(PARSER,
  1846. ("[UcpParseHttpResponse]: Invalid state \n"));
  1847. return STATUS_INVALID_NETWORK_RESPONSE;
  1848. } // case
  1849. }
  1850. if(pRequest->ParseState != UcParseDone)
  1851. {
  1852. //
  1853. // Ideally, we want to do this check inside UcParseEntityBody -
  1854. // however, if BytesIndicated == 0 adn we are done, we might not
  1855. // get a chance to even go there.
  1856. //
  1857. if(pRequest->ParseState == UcParseEntityBody &&
  1858. pRequest->ResponseContentLengthSpecified &&
  1859. pRequest->ResponseContentLength == 0)
  1860. {
  1861. pRequest->ParseState = UcParseDone;
  1862. return STATUS_SUCCESS;
  1863. }
  1864. return STATUS_MORE_PROCESSING_REQUIRED;
  1865. }
  1866. else
  1867. {
  1868. return STATUS_SUCCESS;
  1869. }
  1870. }
  1871. /***************************************************************************++
  1872. Routine Description:
  1873. This is the main routine that gets called from the TDI receive indication
  1874. handler. It merges the indications, allocates buffers (if required) and
  1875. kicks of the Parser.
  1876. Arguments:
  1877. pConnectionContext - The UC_CLIENT_CONNECTION structure.
  1878. pIndicatedBuffer - The current Indication
  1879. BytesIndicated - Size of the current Indication.
  1880. UnreceivedLength - Bytes the transport has, but arent in buffer.
  1881. Return Value:
  1882. NTSTATUS - Completion status.
  1883. STATUS_SUCCESS : Parsed or buffered the indication.
  1884. STATUS_INSUFFICIENT_RESOURCES : Out of memory. This will result in a
  1885. connection tear down.
  1886. STATUS_INVALID_NETWORK_RESPONSE : Illegal HTTP response, mismatched
  1887. response.
  1888. --***************************************************************************/
  1889. NTSTATUS
  1890. UcHandleResponse(IN PVOID pListeningContext,
  1891. IN PVOID pConnectionContext,
  1892. IN PVOID pIndicatedBuffer,
  1893. IN ULONG BytesIndicated,
  1894. IN ULONG UnreceivedLength,
  1895. OUT PULONG pBytesTaken)
  1896. {
  1897. ULONG BytesTaken;
  1898. ULONG i;
  1899. PUC_CLIENT_CONNECTION pConnection;
  1900. PUCHAR pIndication, Indication[2], pOldIndication;
  1901. ULONG IndicationLength[2];
  1902. ULONG IndicationCount;
  1903. PUC_HTTP_REQUEST pRequest;
  1904. NTSTATUS Status;
  1905. PLIST_ENTRY pList;
  1906. KIRQL OldIrql;
  1907. ULONG OriginalBytesIndicated;
  1908. ULONG OldIndicationBytesAllocated;
  1909. BOOLEAN DoneWithLoop = FALSE;
  1910. UNREFERENCED_PARAMETER(pListeningContext);
  1911. UNREFERENCED_PARAMETER(UnreceivedLength);
  1912. OriginalBytesIndicated = BytesIndicated;
  1913. OldIndicationBytesAllocated = 0;
  1914. *pBytesTaken = 0;
  1915. pConnection = (PUC_CLIENT_CONNECTION) pConnectionContext;
  1916. ASSERT( UC_IS_VALID_CLIENT_CONNECTION(pConnection) );
  1917. //
  1918. // Right now, no body calls the client receive function with
  1919. // Unreceived length. In TDI receive handler, we always drain
  1920. // out the data before calling UcHandleResponse.
  1921. //
  1922. ASSERT(UnreceivedLength == 0);
  1923. //
  1924. // We might have got insufficient indication from a prior indication.
  1925. // Let's see if we need to merge this.
  1926. //
  1927. UcpMergeIndications(pConnection,
  1928. (PUCHAR)pIndicatedBuffer,
  1929. BytesIndicated,
  1930. Indication,
  1931. IndicationLength,
  1932. &IndicationCount);
  1933. ASSERT( (IndicationCount == 1 || IndicationCount == 2) );
  1934. //
  1935. // Begin parsing.
  1936. //
  1937. for(i=0; !DoneWithLoop && i<IndicationCount; i++)
  1938. {
  1939. BytesIndicated = IndicationLength[i];
  1940. pIndication = Indication[i];
  1941. while(BytesIndicated)
  1942. {
  1943. //
  1944. // We first need to pick the first request that got submitted to
  1945. // TDI. We need this to match responses to requests. There will be
  1946. // an entry in this list even if the app did not submit an output
  1947. // buffer with the request.
  1948. //
  1949. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  1950. //
  1951. // If the connection is being cleaned up, we should not even
  1952. // be here. Ideally, this will never happen, because TDI will
  1953. // not call our cleanup handler till all outstanding receives
  1954. // are complete.
  1955. //
  1956. // However, when we go over SSL, we buffer the data & complete
  1957. // TDI's receive thread.
  1958. //
  1959. if(pConnection->ConnectionState ==
  1960. UcConnectStateConnectCleanup ||
  1961. pConnection->ConnectionState ==
  1962. UcConnectStateConnectCleanupBegin)
  1963. {
  1964. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1965. UlTrace(PARSER,
  1966. ("[UcHandleResponse]: Connection cleaned \n"));
  1967. return STATUS_INVALID_NETWORK_RESPONSE;
  1968. }
  1969. if(IsListEmpty(&pConnection->SentRequestList))
  1970. {
  1971. //
  1972. // This can happen if the server sends a screwed up response.
  1973. // we'll never be able to match responses with requests. We are
  1974. // forced to tear down the connection.
  1975. //
  1976. //
  1977. // We won't do any clean-up here - This status code will cause
  1978. // the connection to get torn down and we'll localize all the
  1979. // conneciton cleanup code.
  1980. //
  1981. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1982. UlTrace(PARSER,
  1983. ("[UcHandleResponse]: Malformed HTTP packet \n"));
  1984. return STATUS_INVALID_NETWORK_RESPONSE;
  1985. }
  1986. pList = (&pConnection->SentRequestList)->Flink;
  1987. pRequest = CONTAINING_RECORD(pList, UC_HTTP_REQUEST, Linkage);
  1988. if(pRequest->ParseState == UcParseDone)
  1989. {
  1990. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  1991. return STATUS_INVALID_NETWORK_RESPONSE;
  1992. }
  1993. switch(pRequest->RequestState)
  1994. {
  1995. case UcRequestStateSent:
  1996. // Received first byte of data but haven't got called
  1997. // in send complete handler.
  1998. pRequest->RequestState =
  1999. UcRequestStateNoSendCompletePartialData;
  2000. break;
  2001. case UcRequestStateNoSendCompletePartialData:
  2002. // Received more data but still haven't got called
  2003. // in send complete handler. We'll remain in the same
  2004. // state.
  2005. break;
  2006. case UcRequestStateSendCompleteNoData:
  2007. // We have been called in Send complete & are receiving
  2008. // the first byte of data.
  2009. pRequest->RequestState =
  2010. UcRequestStateSendCompletePartialData;
  2011. break;
  2012. case UcRequestStateSendCompletePartialData:
  2013. // We have been called in Send complete & are receiving
  2014. // data.
  2015. break;
  2016. default:
  2017. ASSERT(0);
  2018. break;
  2019. }
  2020. if(UcpReferenceForReceive(pRequest) == FALSE)
  2021. {
  2022. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2023. UlTrace(PARSER,
  2024. ("[UcHandleResponse]: Receive cancelled \n"));
  2025. return STATUS_CANCELLED;
  2026. }
  2027. pConnection->Flags |= CLIENT_CONN_FLAG_RECV_BUSY;
  2028. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2029. //
  2030. // Given a request & response buffer, we will loop till we parse
  2031. // out this completly.
  2032. //
  2033. while(TRUE)
  2034. {
  2035. Status = UcpParseHttpResponse(pRequest,
  2036. pIndication,
  2037. BytesIndicated,
  2038. &BytesTaken);
  2039. //
  2040. // Even if there is an error, we could have consumed some
  2041. // amount of data.
  2042. //
  2043. BytesIndicated -= BytesTaken;
  2044. pIndication += BytesTaken;
  2045. ASSERT((LONG)BytesIndicated >= 0);
  2046. if(Status == STATUS_SUCCESS)
  2047. {
  2048. //
  2049. // This one worked! Complete the IRP that got pended.
  2050. //
  2051. UcpHandleParsedRequest(pRequest,
  2052. &pIndication,
  2053. &BytesIndicated,
  2054. BytesTaken
  2055. );
  2056. UcpDereferenceForReceive(pRequest);
  2057. break;
  2058. }
  2059. else
  2060. {
  2061. if(Status == STATUS_MORE_PROCESSING_REQUIRED)
  2062. {
  2063. UcpDereferenceForReceive(pRequest);
  2064. if(BytesIndicated == 0)
  2065. {
  2066. // This just means that this indication was parsed
  2067. // completly, but we did not reach the end of the
  2068. // response. Let's move on to the next indication.
  2069. // This will take us out of the While(TRUE) loop
  2070. // as well as while(BytesIndicated) loop.
  2071. break;
  2072. }
  2073. else if(DoneWithLoop || i == IndicationCount - 1)
  2074. {
  2075. // We ran out of buffer space for the last
  2076. // indication. This could either be a TDI
  2077. // indication or a "merged" indication
  2078. //
  2079. // If its a TDI indication we have to copy since
  2080. // we don't own the TDI buffers. If its our
  2081. // indication, we still have to copy since some
  2082. // portion of it might have got consumed by the
  2083. // parser & we care only about the remaining.
  2084. pOldIndication =
  2085. pConnection->MergeIndication.pBuffer;
  2086. OldIndicationBytesAllocated =
  2087. pConnection->MergeIndication.BytesAllocated;
  2088. pConnection->MergeIndication.pBuffer =
  2089. (PUCHAR) UL_ALLOCATE_POOL_WITH_QUOTA(
  2090. NonPagedPool,
  2091. BytesIndicated +
  2092. UC_INSUFFICIENT_INDICATION_EXTRA_BUFFER,
  2093. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2094. pConnection->pServerInfo->pProcess
  2095. );
  2096. if(!pConnection->MergeIndication.pBuffer)
  2097. {
  2098. if(pOldIndication)
  2099. {
  2100. UL_FREE_POOL_WITH_QUOTA(
  2101. pOldIndication,
  2102. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2103. NonPagedPool,
  2104. OldIndicationBytesAllocated,
  2105. pConnection->pServerInfo->pProcess
  2106. );
  2107. }
  2108. UlAcquireSpinLock(&pConnection->SpinLock,
  2109. &OldIrql);
  2110. UcClearConnectionBusyFlag(
  2111. pConnection,
  2112. CLIENT_CONN_FLAG_RECV_BUSY,
  2113. OldIrql,
  2114. FALSE
  2115. );
  2116. return STATUS_INSUFFICIENT_RESOURCES;
  2117. }
  2118. pConnection->MergeIndication.BytesAllocated =
  2119. BytesIndicated +
  2120. UC_INSUFFICIENT_INDICATION_EXTRA_BUFFER;
  2121. pConnection->MergeIndication.BytesWritten =
  2122. BytesIndicated;
  2123. RtlCopyMemory(
  2124. pConnection->MergeIndication.pBuffer,
  2125. pIndication,
  2126. BytesIndicated
  2127. );
  2128. if(pOldIndication)
  2129. {
  2130. UL_FREE_POOL_WITH_QUOTA(
  2131. pOldIndication,
  2132. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2133. NonPagedPool,
  2134. OldIndicationBytesAllocated,
  2135. pConnection->pServerInfo->pProcess
  2136. );
  2137. }
  2138. //
  2139. // Let's pretend as if we have read all of the data.
  2140. //
  2141. *pBytesTaken = OriginalBytesIndicated;
  2142. UlAcquireSpinLock(&pConnection->SpinLock,
  2143. &OldIrql);
  2144. UcClearConnectionBusyFlag(
  2145. pConnection,
  2146. CLIENT_CONN_FLAG_RECV_BUSY,
  2147. OldIrql,
  2148. FALSE
  2149. );
  2150. return STATUS_SUCCESS;
  2151. }
  2152. else
  2153. {
  2154. //
  2155. // Our merge did not go well. We have to copy more
  2156. // data from the TDI indication into this
  2157. // and continue. To keep things simple, we'll just
  2158. // copy everything.
  2159. //
  2160. ASSERT(i==0);
  2161. ASSERT(pConnection->MergeIndication.pBuffer);
  2162. if(pConnection->MergeIndication.BytesAllocated <
  2163. (BytesIndicated + IndicationLength[i+1] +
  2164. UC_INSUFFICIENT_INDICATION_EXTRA_BUFFER)
  2165. )
  2166. {
  2167. pOldIndication =
  2168. pConnection->MergeIndication.pBuffer;
  2169. OldIndicationBytesAllocated =
  2170. pConnection->MergeIndication.BytesAllocated;
  2171. pConnection->MergeIndication.pBuffer =
  2172. (PUCHAR) UL_ALLOCATE_POOL_WITH_QUOTA(
  2173. NonPagedPool,
  2174. BytesIndicated+ IndicationLength[i+1]+
  2175. UC_INSUFFICIENT_INDICATION_EXTRA_BUFFER,
  2176. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2177. pConnection->pServerInfo->pProcess
  2178. );
  2179. if(!pConnection->MergeIndication.pBuffer)
  2180. {
  2181. UL_FREE_POOL_WITH_QUOTA(
  2182. pOldIndication,
  2183. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2184. NonPagedPool,
  2185. OldIndicationBytesAllocated,
  2186. pConnection->pServerInfo->pProcess
  2187. );
  2188. UlAcquireSpinLock(&pConnection->SpinLock,
  2189. &OldIrql);
  2190. UcClearConnectionBusyFlag(
  2191. pConnection,
  2192. CLIENT_CONN_FLAG_RECV_BUSY,
  2193. OldIrql,
  2194. FALSE
  2195. );
  2196. return STATUS_INSUFFICIENT_RESOURCES;
  2197. }
  2198. pConnection->MergeIndication.BytesAllocated =
  2199. BytesIndicated + IndicationLength[i+1] +
  2200. UC_INSUFFICIENT_INDICATION_EXTRA_BUFFER;
  2201. }
  2202. else
  2203. {
  2204. pOldIndication = 0;
  2205. }
  2206. RtlCopyMemory(
  2207. pConnection->MergeIndication.pBuffer,
  2208. pIndication,
  2209. BytesIndicated
  2210. );
  2211. RtlCopyMemory(
  2212. pConnection->MergeIndication.pBuffer +
  2213. BytesIndicated,
  2214. Indication[i+1],
  2215. IndicationLength[i+1]
  2216. );
  2217. if(pOldIndication)
  2218. {
  2219. UL_FREE_POOL_WITH_QUOTA(
  2220. pOldIndication,
  2221. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2222. NonPagedPool,
  2223. OldIndicationBytesAllocated,
  2224. pConnection->pServerInfo->pProcess
  2225. );
  2226. }
  2227. pConnection->MergeIndication.BytesWritten =
  2228. BytesIndicated + IndicationLength[i+1];
  2229. //
  2230. // Fix up all the variables so that we run through
  2231. // the loop only once with the new buffer.
  2232. //
  2233. pIndication =
  2234. pConnection->MergeIndication.pBuffer;
  2235. BytesIndicated =
  2236. pConnection->MergeIndication.BytesWritten;
  2237. DoneWithLoop = TRUE;
  2238. //
  2239. // This will take us out of the while(TRUE) loop.
  2240. // so we will resume at while(BytesIndicated) loop
  2241. // pick the next request & party on.
  2242. //
  2243. break;
  2244. }
  2245. }
  2246. else if(Status == STATUS_INSUFFICIENT_RESOURCES)
  2247. {
  2248. //
  2249. // We ran out of output buffer space. Let's get more
  2250. // buffer to hold the response.
  2251. //
  2252. Status = UcpGetResponseBuffer(pRequest,
  2253. BytesIndicated,
  2254. 0);
  2255. if(!NT_SUCCESS(Status))
  2256. {
  2257. UcpDereferenceForReceive(pRequest);
  2258. UlAcquireSpinLock(&pConnection->SpinLock,
  2259. &OldIrql);
  2260. UcClearConnectionBusyFlag(
  2261. pConnection,
  2262. CLIENT_CONN_FLAG_RECV_BUSY,
  2263. OldIrql,
  2264. FALSE
  2265. );
  2266. return Status;
  2267. }
  2268. //
  2269. // since we have got more buffer, continue parsing the
  2270. // response.
  2271. //
  2272. continue;
  2273. }
  2274. else
  2275. {
  2276. //
  2277. // Some other error - Bail right away.
  2278. //
  2279. pRequest->ParseState = UcParseError;
  2280. UcpDereferenceForReceive(pRequest);
  2281. // The common parser returns
  2282. // STATUS_INVALID_DEVICE_REQUEST if it finds an
  2283. // illegal response. A better error code would be
  2284. // STATUS_INVALID_NETWORK_RESPONSE. Since we don't
  2285. // want to change the common parser, we'll just eat
  2286. // this error code.
  2287. if(STATUS_INVALID_DEVICE_REQUEST == Status)
  2288. {
  2289. Status = STATUS_INVALID_NETWORK_RESPONSE;
  2290. }
  2291. UlAcquireSpinLock(&pConnection->SpinLock,
  2292. &OldIrql);
  2293. UcClearConnectionBusyFlag(
  2294. pConnection,
  2295. CLIENT_CONN_FLAG_RECV_BUSY,
  2296. OldIrql,
  2297. FALSE
  2298. );
  2299. return Status;
  2300. }
  2301. }
  2302. //
  2303. // We can never get here.
  2304. //
  2305. // ASSERT(FALSE);
  2306. } // while(TRUE)
  2307. UlAcquireSpinLock(&pConnection->SpinLock,
  2308. &OldIrql);
  2309. UcClearConnectionBusyFlag(
  2310. pConnection,
  2311. CLIENT_CONN_FLAG_RECV_BUSY,
  2312. OldIrql,
  2313. FALSE
  2314. );
  2315. } // while(BytesIndicated)
  2316. } // for(i=0; i<IndicationCount; i++)
  2317. //
  2318. // If we have reached here, we have successfully parsed out the
  2319. // buffers
  2320. if(pConnection->MergeIndication.pBuffer)
  2321. {
  2322. UL_FREE_POOL_WITH_QUOTA(
  2323. pConnection->MergeIndication.pBuffer,
  2324. UC_RESPONSE_TDI_BUFFER_POOL_TAG,
  2325. NonPagedPool,
  2326. pConnection->MergeIndication.BytesAllocated,
  2327. pConnection->pServerInfo->pProcess
  2328. );
  2329. pConnection->MergeIndication.pBuffer = 0;
  2330. }
  2331. *pBytesTaken = OriginalBytesIndicated;
  2332. return STATUS_SUCCESS;
  2333. }
  2334. /***************************************************************************++
  2335. Routine Description:
  2336. This routine handles failures to the CONNECT verb. In such cases, we have
  2337. to pick up the head request from the pending list that initiated the
  2338. connect & fail it.
  2339. Arguments:
  2340. pConnection - pointer to the connection
  2341. Return Value:
  2342. None
  2343. --***************************************************************************/
  2344. VOID
  2345. UcpHandleConnectVerbFailure(
  2346. IN PUC_CLIENT_CONNECTION pConnection,
  2347. OUT PUCHAR *pIndication,
  2348. OUT PULONG BytesIndicated,
  2349. IN ULONG BytesTaken
  2350. )
  2351. {
  2352. PLIST_ENTRY pEntry;
  2353. KIRQL OldIrql;
  2354. PUC_HTTP_REQUEST pRequest;
  2355. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  2356. //
  2357. // Remove the dummy request form the sent list.
  2358. //
  2359. pEntry = RemoveHeadList(&pConnection->SentRequestList);
  2360. //
  2361. // Initialize it so that we won't remove it again.
  2362. //
  2363. InitializeListHead(pEntry);
  2364. if(pConnection->ConnectionState == UcConnectStateProxySslConnect)
  2365. {
  2366. pConnection->ConnectionState = UcConnectStateConnectComplete;
  2367. }
  2368. //
  2369. // Remove the head request from the pending list &
  2370. // insert in the sent request list.
  2371. //
  2372. ASSERT(IsListEmpty(&pConnection->SentRequestList));
  2373. if(!IsListEmpty(&pConnection->PendingRequestList))
  2374. {
  2375. pEntry = RemoveHeadList(&pConnection->PendingRequestList);
  2376. pRequest = CONTAINING_RECORD(pEntry,
  2377. UC_HTTP_REQUEST,
  2378. Linkage);
  2379. InsertHeadList(&pConnection->SentRequestList, pEntry);
  2380. //
  2381. // Fake a send completion.
  2382. //
  2383. ASSERT(pRequest->RequestState == UcRequestStateCaptured);
  2384. pRequest->RequestState = UcRequestStateSent;
  2385. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2386. UcRestartMdlSend(pRequest,
  2387. STATUS_SUCCESS,
  2388. 0
  2389. );
  2390. *pIndication -= BytesTaken;
  2391. *BytesIndicated += BytesTaken;
  2392. }
  2393. }
  2394. /***************************************************************************++
  2395. Routine Description:
  2396. This routine does post parsing book keeping for a request. We update the
  2397. auth cache, proxy auth cache, re-issue NTLM requests, etc, etc.
  2398. Arguments:
  2399. pRequest - The fully parsed request
  2400. Return Value:
  2401. None
  2402. --***************************************************************************/
  2403. VOID
  2404. UcpHandleParsedRequest(
  2405. IN PUC_HTTP_REQUEST pRequest,
  2406. OUT PUCHAR *pIndication,
  2407. OUT PULONG BytesIndicated,
  2408. IN ULONG BytesTaken
  2409. )
  2410. {
  2411. PUC_CLIENT_CONNECTION pConnection;
  2412. KIRQL OldIrql;
  2413. pConnection = pRequest->pConnection;
  2414. //
  2415. // See if we have to issue a close. There are two cases - If the server
  2416. // has sent a Connection: close header OR if we are doing error detection
  2417. // for POSTs.
  2418. //
  2419. if(
  2420. (pRequest->ResponseConnectionClose &&
  2421. !pRequest->RequestConnectionClose) ||
  2422. (!(pRequest->ResponseStatusCode >= 200 &&
  2423. pRequest->ResponseStatusCode <=299) &&
  2424. !pRequest->RequestFlags.NoRequestEntityBodies &&
  2425. !pRequest->Renegotiate)
  2426. )
  2427. {
  2428. // Error Detection for POSTS:
  2429. //
  2430. // The scenario here is that the client sends a request with
  2431. // entity body, has not sent all of the entity in one call & is
  2432. // hitting a URI that triggers a error response (e.g. 401).
  2433. // As per section 8.2.2, we have to terminate the entity send when
  2434. // we see the error response. Now, we can do this in two ways. If the
  2435. // request is sent using content-length encoding, we are forced to
  2436. // close the connection. If the request is sent with chunked encoding,
  2437. // we can send a 0 length chunk.
  2438. //
  2439. // However, we will ALWAYS close the connection. There are two reasons
  2440. // behind this design rationale
  2441. // a. Simplifies the code.
  2442. // b. Allows us to expose a consistent API semantic. Subsequent
  2443. // HttpSendRequestEntityBody will fail with
  2444. // STATUS_CONNECTION_DISCONNECTED. When this happens, the
  2445. // app CAN see the response by posting a response buffer.
  2446. UC_CLOSE_CONNECTION(pConnection, FALSE, STATUS_CONNECTION_DISCONNECTED);
  2447. }
  2448. //
  2449. // Now, we have to complete the IRP.
  2450. //
  2451. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  2452. //
  2453. // If we have allocated buffers, we need to adjust BytesWritten
  2454. //
  2455. if(pRequest->CurrentBuffer.pCurrentBuffer)
  2456. {
  2457. pRequest->CurrentBuffer.pCurrentBuffer->Flags |=
  2458. UC_RESPONSE_BUFFER_FLAG_READY;
  2459. pRequest->CurrentBuffer.pCurrentBuffer->BytesWritten =
  2460. pRequest->CurrentBuffer.BytesAllocated -
  2461. pRequest->CurrentBuffer.BytesAvailable;
  2462. }
  2463. switch(pRequest->RequestState)
  2464. {
  2465. case UcRequestStateNoSendCompletePartialData:
  2466. // Request got parsed completly before we got called in
  2467. // the send complete.
  2468. pRequest->RequestState = UcRequestStateNoSendCompleteFullData;
  2469. //
  2470. // If we are pipelining sends, we don't want the next response
  2471. // to be re-parsed into this already parsed request.
  2472. //
  2473. if(!pRequest->Renegotiate)
  2474. {
  2475. RemoveEntryList(&pRequest->Linkage);
  2476. InitializeListHead(&pRequest->Linkage);
  2477. }
  2478. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2479. break;
  2480. case UcRequestStateSendCompletePartialData:
  2481. if(pRequest->RequestFlags.Cancelled == FALSE)
  2482. {
  2483. pRequest->RequestState = UcRequestStateResponseParsed;
  2484. UcCompleteParsedRequest(
  2485. pRequest,
  2486. pRequest->RequestStatus,
  2487. TRUE,
  2488. OldIrql);
  2489. }
  2490. else
  2491. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2492. break;
  2493. default:
  2494. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2495. break;
  2496. }
  2497. if(pRequest->RequestFlags.ProxySslConnect &&
  2498. pRequest->Renegotiate == FALSE)
  2499. {
  2500. if(pRequest->ResponseStatusCode != 200)
  2501. {
  2502. // Some real error, we need to show this to the app.
  2503. UcpHandleConnectVerbFailure(
  2504. pConnection,
  2505. pIndication,
  2506. BytesIndicated,
  2507. BytesTaken
  2508. );
  2509. }
  2510. else
  2511. {
  2512. UlAcquireSpinLock(&pConnection->SpinLock, &OldIrql);
  2513. if(pConnection->ConnectionState == UcConnectStateProxySslConnect)
  2514. {
  2515. pConnection->ConnectionState =
  2516. UcConnectStateProxySslConnectComplete;
  2517. }
  2518. UlReleaseSpinLock(&pConnection->SpinLock, OldIrql);
  2519. }
  2520. }
  2521. }
  2522. /***************************************************************************++
  2523. Routine Description:
  2524. This routine references a request for the receive parser.
  2525. Arguments:
  2526. pRequest - The request
  2527. Return Value:
  2528. None
  2529. --***************************************************************************/
  2530. BOOLEAN
  2531. UcpReferenceForReceive(
  2532. IN PUC_HTTP_REQUEST pRequest
  2533. )
  2534. {
  2535. LONG OldReceiveBusy;
  2536. //
  2537. // Flag this request so that it doesn't get cancelled beneath us
  2538. //
  2539. OldReceiveBusy = InterlockedExchange(
  2540. &pRequest->ReceiveBusy,
  2541. UC_REQUEST_RECEIVE_BUSY
  2542. );
  2543. if(OldReceiveBusy == UC_REQUEST_RECEIVE_CANCELLED)
  2544. {
  2545. // This request already got cancelled
  2546. return FALSE;
  2547. }
  2548. ASSERT(OldReceiveBusy == UC_REQUEST_RECEIVE_READY);
  2549. UC_REFERENCE_REQUEST(pRequest);
  2550. return TRUE;
  2551. }
  2552. /***************************************************************************++
  2553. Routine Description:
  2554. This routine de-references a request for the receive parser. Resumes
  2555. any cleanup if required.
  2556. Arguments:
  2557. pRequest - The request
  2558. Return Value:
  2559. None
  2560. --***************************************************************************/
  2561. VOID
  2562. UcpDereferenceForReceive(
  2563. IN PUC_HTTP_REQUEST pRequest
  2564. )
  2565. {
  2566. LONG OldReceiveBusy;
  2567. OldReceiveBusy = InterlockedExchange(
  2568. &pRequest->ReceiveBusy,
  2569. UC_REQUEST_RECEIVE_READY
  2570. );
  2571. if(OldReceiveBusy == UC_REQUEST_RECEIVE_CANCELLED)
  2572. {
  2573. //
  2574. // The reqeust got cancelled when the receive thread was running,
  2575. // we now have to resume it.
  2576. //
  2577. IoAcquireCancelSpinLock(&pRequest->RequestIRP->CancelIrql);
  2578. UC_WRITE_TRACE_LOG(
  2579. g_pUcTraceLog,
  2580. UC_ACTION_REQUEST_CLEAN_RESUMED,
  2581. pRequest->pConnection,
  2582. pRequest,
  2583. pRequest->RequestIRP,
  2584. UlongToPtr((ULONG)STATUS_CANCELLED)
  2585. );
  2586. UcCancelSentRequest(
  2587. NULL,
  2588. pRequest->RequestIRP
  2589. );
  2590. }
  2591. else
  2592. {
  2593. ASSERT(OldReceiveBusy == UC_REQUEST_RECEIVE_BUSY);
  2594. }
  2595. UC_DEREFERENCE_REQUEST(pRequest);
  2596. }