2 Http IO Helper Library.
4 (C) Copyright 2020 Hewlett-Packard Development Company, L.P.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Protocol/Http.h>
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/HttpIoLib.h>
16 #include <Library/MemoryAllocationLib.h>
17 #include <Library/PrintLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
21 Notify the callback function when an event is triggered.
23 @param[in] Context The opaque parameter to the function.
32 *((BOOLEAN
*) Context
) = TRUE
;
36 Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.
38 @param[in] Event The event signaled.
39 @param[in] Context The opaque parameter to the function.
50 // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK
52 QueueDpc (TPL_CALLBACK
, HttpIoNotifyDpc
, Context
);
56 Destroy the HTTP_IO and release the resources.
58 @param[in] HttpIo The HTTP_IO which wraps the HTTP service to be destroyed.
66 EFI_HTTP_PROTOCOL
*Http
;
73 Event
= HttpIo
->ReqToken
.Event
;
75 gBS
->CloseEvent (Event
);
78 Event
= HttpIo
->RspToken
.Event
;
80 gBS
->CloseEvent (Event
);
83 Event
= HttpIo
->TimeoutEvent
;
85 gBS
->CloseEvent (Event
);
90 Http
->Configure (Http
, NULL
);
93 &gEfiHttpProtocolGuid
,
99 NetLibDestroyServiceChild (
102 &gEfiHttpServiceBindingProtocolGuid
,
108 Create a HTTP_IO to access the HTTP service. It will create and configure
111 @param[in] Image The handle of the driver image.
112 @param[in] Controller The handle of the controller.
113 @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
114 @param[in] ConfigData The HTTP_IO configuration data ,
115 NULL means not to configure the HTTP child.
116 @param[in] Callback Callback function which will be invoked when specified
117 HTTP_IO_CALLBACK_EVENT happened.
118 @param[in] Context The Context data which will be passed to the Callback function.
119 @param[out] HttpIo The HTTP_IO.
121 @retval EFI_SUCCESS The HTTP_IO is created and configured.
122 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
123 @retval EFI_UNSUPPORTED One or more of the control options are not
124 supported in the implementation.
125 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
126 @retval Others Failed to create the HTTP_IO or configure it.
132 IN EFI_HANDLE Controller
,
134 IN HTTP_IO_CONFIG_DATA
*ConfigData OPTIONAL
,
135 IN HTTP_IO_CALLBACK Callback
,
141 EFI_HTTP_CONFIG_DATA HttpConfigData
;
142 EFI_HTTPv4_ACCESS_POINT Http4AccessPoint
;
143 EFI_HTTPv6_ACCESS_POINT Http6AccessPoint
;
144 EFI_HTTP_PROTOCOL
*Http
;
147 if ((Image
== NULL
) || (Controller
== NULL
) || (HttpIo
== NULL
)) {
148 return EFI_INVALID_PARAMETER
;
151 if (IpVersion
!= IP_VERSION_4
&& IpVersion
!= IP_VERSION_6
) {
152 return EFI_UNSUPPORTED
;
155 ZeroMem (HttpIo
, sizeof (HTTP_IO
));
156 ZeroMem (&HttpConfigData
, sizeof (EFI_HTTP_CONFIG_DATA
));
159 // Create the HTTP child instance and get the HTTP protocol.
161 Status
= NetLibCreateServiceChild (
164 &gEfiHttpServiceBindingProtocolGuid
,
167 if (EFI_ERROR (Status
)) {
171 Status
= gBS
->OpenProtocol (
173 &gEfiHttpProtocolGuid
,
177 EFI_OPEN_PROTOCOL_BY_DRIVER
179 if (EFI_ERROR (Status
) || (Http
== NULL
)) {
184 // Init the configuration data and configure the HTTP child.
186 HttpIo
->Image
= Image
;
187 HttpIo
->Controller
= Controller
;
188 HttpIo
->IpVersion
= IpVersion
;
190 HttpIo
->Callback
= Callback
;
191 HttpIo
->Context
= Context
;
192 HttpIo
->Timeout
= PcdGet32 (PcdHttpIoTimeout
);
194 if (ConfigData
!= NULL
) {
195 if (HttpIo
->IpVersion
== IP_VERSION_4
) {
196 HttpConfigData
.LocalAddressIsIPv6
= FALSE
;
197 HttpConfigData
.HttpVersion
= ConfigData
->Config4
.HttpVersion
;
198 HttpConfigData
.TimeOutMillisec
= ConfigData
->Config4
.RequestTimeOut
;
200 Http4AccessPoint
.UseDefaultAddress
= ConfigData
->Config4
.UseDefaultAddress
;
201 Http4AccessPoint
.LocalPort
= ConfigData
->Config4
.LocalPort
;
202 IP4_COPY_ADDRESS (&Http4AccessPoint
.LocalAddress
, &ConfigData
->Config4
.LocalIp
);
203 IP4_COPY_ADDRESS (&Http4AccessPoint
.LocalSubnet
, &ConfigData
->Config4
.SubnetMask
);
204 HttpConfigData
.AccessPoint
.IPv4Node
= &Http4AccessPoint
;
206 HttpConfigData
.LocalAddressIsIPv6
= TRUE
;
207 HttpConfigData
.HttpVersion
= ConfigData
->Config6
.HttpVersion
;
208 HttpConfigData
.TimeOutMillisec
= ConfigData
->Config6
.RequestTimeOut
;
210 Http6AccessPoint
.LocalPort
= ConfigData
->Config6
.LocalPort
;
211 IP6_COPY_ADDRESS (&Http6AccessPoint
.LocalAddress
, &ConfigData
->Config6
.LocalIp
);
212 HttpConfigData
.AccessPoint
.IPv6Node
= &Http6AccessPoint
;
215 Status
= Http
->Configure (Http
, &HttpConfigData
);
216 if (EFI_ERROR (Status
)) {
222 // Create events for variuos asynchronous operations.
224 Status
= gBS
->CreateEvent (
231 if (EFI_ERROR (Status
)) {
234 HttpIo
->ReqToken
.Event
= Event
;
235 HttpIo
->ReqToken
.Message
= &HttpIo
->ReqMessage
;
237 Status
= gBS
->CreateEvent (
244 if (EFI_ERROR (Status
)) {
247 HttpIo
->RspToken
.Event
= Event
;
248 HttpIo
->RspToken
.Message
= &HttpIo
->RspMessage
;
251 // Create TimeoutEvent for response
253 Status
= gBS
->CreateEvent (
260 if (EFI_ERROR (Status
)) {
263 HttpIo
->TimeoutEvent
= Event
;
267 HttpIoDestroyIo (HttpIo
);
273 Synchronously send a HTTP REQUEST message to the server.
275 @param[in] HttpIo The HttpIo wrapping the HTTP service.
276 @param[in] Request A pointer to storage such data as URL and HTTP method.
277 @param[in] HeaderCount Number of HTTP header structures in Headers list.
278 @param[in] Headers Array containing list of HTTP headers.
279 @param[in] BodyLength Length in bytes of the HTTP body.
280 @param[in] Body Body associated with the HTTP request.
282 @retval EFI_SUCCESS The HTTP request is trasmitted.
283 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
284 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
285 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
286 @retval Others Other errors as indicated.
292 IN EFI_HTTP_REQUEST_DATA
*Request
,
293 IN UINTN HeaderCount
,
294 IN EFI_HTTP_HEADER
*Headers
,
300 EFI_HTTP_PROTOCOL
*Http
;
302 if (HttpIo
== NULL
|| HttpIo
->Http
== NULL
) {
303 return EFI_INVALID_PARAMETER
;
306 HttpIo
->ReqToken
.Status
= EFI_NOT_READY
;
307 HttpIo
->ReqToken
.Message
->Data
.Request
= Request
;
308 HttpIo
->ReqToken
.Message
->HeaderCount
= HeaderCount
;
309 HttpIo
->ReqToken
.Message
->Headers
= Headers
;
310 HttpIo
->ReqToken
.Message
->BodyLength
= BodyLength
;
311 HttpIo
->ReqToken
.Message
->Body
= Body
;
313 if (HttpIo
->Callback
!= NULL
) {
314 Status
= HttpIo
->Callback (
316 HttpIo
->ReqToken
.Message
,
319 if (EFI_ERROR (Status
)) {
325 // Queue the request token to HTTP instances.
328 HttpIo
->IsTxDone
= FALSE
;
329 Status
= Http
->Request (
333 if (EFI_ERROR (Status
)) {
338 // Poll the network until transmit finish.
340 while (!HttpIo
->IsTxDone
) {
344 return HttpIo
->ReqToken
.Status
;
348 Synchronously receive a HTTP RESPONSE message from the server.
350 @param[in] HttpIo The HttpIo wrapping the HTTP service.
351 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).
352 FALSE to continue receive the previous response message.
353 @param[out] ResponseData Point to a wrapper of the received response data.
355 @retval EFI_SUCCESS The HTTP response is received.
356 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
357 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
358 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
359 @retval Others Other errors as indicated.
365 IN BOOLEAN RecvMsgHeader
,
366 OUT HTTP_IO_RESPONSE_DATA
*ResponseData
370 EFI_HTTP_PROTOCOL
*Http
;
372 if (HttpIo
== NULL
|| HttpIo
->Http
== NULL
|| ResponseData
== NULL
) {
373 return EFI_INVALID_PARAMETER
;
377 // Queue the response token to HTTP instances.
379 HttpIo
->RspToken
.Status
= EFI_NOT_READY
;
381 HttpIo
->RspToken
.Message
->Data
.Response
= &ResponseData
->Response
;
383 HttpIo
->RspToken
.Message
->Data
.Response
= NULL
;
385 HttpIo
->RspToken
.Message
->HeaderCount
= 0;
386 HttpIo
->RspToken
.Message
->Headers
= NULL
;
387 HttpIo
->RspToken
.Message
->BodyLength
= ResponseData
->BodyLength
;
388 HttpIo
->RspToken
.Message
->Body
= ResponseData
->Body
;
391 HttpIo
->IsRxDone
= FALSE
;
394 // Start the timer, and wait Timeout seconds to receive the header packet.
396 Status
= gBS
->SetTimer (HttpIo
->TimeoutEvent
, TimerRelative
, HttpIo
->Timeout
* TICKS_PER_MS
);
397 if (EFI_ERROR (Status
)) {
401 Status
= Http
->Response (
406 if (EFI_ERROR (Status
)) {
408 // Remove timeout timer from the event list.
410 gBS
->SetTimer (HttpIo
->TimeoutEvent
, TimerCancel
, 0);
415 // Poll the network until receive finish.
417 while (!HttpIo
->IsRxDone
&& EFI_ERROR (gBS
->CheckEvent (HttpIo
->TimeoutEvent
))) {
422 // Remove timeout timer from the event list.
424 gBS
->SetTimer (HttpIo
->TimeoutEvent
, TimerCancel
, 0);
426 if (!HttpIo
->IsRxDone
) {
428 // Timeout occurs, cancel the response token.
430 Http
->Cancel (Http
, &HttpIo
->RspToken
);
432 Status
= EFI_TIMEOUT
;
436 HttpIo
->IsRxDone
= FALSE
;
439 if ((HttpIo
->Callback
!= NULL
) &&
440 (HttpIo
->RspToken
.Status
== EFI_SUCCESS
|| HttpIo
->RspToken
.Status
== EFI_HTTP_ERROR
)) {
441 Status
= HttpIo
->Callback (
443 HttpIo
->RspToken
.Message
,
446 if (EFI_ERROR (Status
)) {
452 // Store the received data into the wrapper.
454 ResponseData
->Status
= HttpIo
->RspToken
.Status
;
455 ResponseData
->HeaderCount
= HttpIo
->RspToken
.Message
->HeaderCount
;
456 ResponseData
->Headers
= HttpIo
->RspToken
.Message
->Headers
;
457 ResponseData
->BodyLength
= HttpIo
->RspToken
.Message
->BodyLength
;
463 Get the value of the content length if there is a "Content-Length" header.
465 @param[in] HeaderCount Number of HTTP header structures in Headers.
466 @param[in] Headers Array containing list of HTTP headers.
467 @param[out] ContentLength Pointer to save the value of the content length.
469 @retval EFI_SUCCESS Successfully get the content length.
470 @retval EFI_NOT_FOUND No "Content-Length" header in the Headers.
474 HttpIoGetContentLength (
475 IN UINTN HeaderCount
,
476 IN EFI_HTTP_HEADER
*Headers
,
477 OUT UINTN
*ContentLength
480 EFI_HTTP_HEADER
*Header
;
482 Header
= HttpFindHeader (HeaderCount
, Headers
, HTTP_HEADER_CONTENT_LENGTH
);
483 if (Header
== NULL
) {
484 return EFI_NOT_FOUND
;
487 return AsciiStrDecimalToUintnS (Header
->FieldValue
, (CHAR8
**) NULL
, ContentLength
);
490 Send HTTP request in chunks.
492 @param[in] HttpIo The HttpIo wrapping the HTTP service.
493 @param[in] SendChunkProcess Pointer to current chunk process status.
494 @param[in] RequestMessage Request to send.
496 @retval EFI_SUCCESS Successfully to send chunk data according to SendChunkProcess.
497 @retval Other Other errors.
501 HttpIoSendChunkedTransfer (
503 IN HTTP_IO_SEND_CHUNK_PROCESS
*SendChunkProcess
,
504 IN EFI_HTTP_MESSAGE
*RequestMessage
508 EFI_HTTP_HEADER
*NewHeaders
;
509 EFI_HTTP_HEADER
*ContentLengthHeader
;
513 UINTN MessageBodyLength
;
515 CHAR8 ChunkLengthStr
[HTTP_IO_CHUNK_SIZE_STRING_LEN
];
516 EFI_HTTP_REQUEST_DATA
*SentRequestData
;
521 ContentLengthHeader
= NULL
;
522 MessageBodyLength
= 0;
524 switch (*SendChunkProcess
) {
525 case HttpIoSendChunkHeaderZeroContent
:
526 ContentLengthHeader
= HttpFindHeader (RequestMessage
->HeaderCount
, RequestMessage
->Headers
, HTTP_HEADER_CONTENT_LENGTH
);
527 if (ContentLengthHeader
== NULL
) {
531 NewHeaders
= AllocateZeroPool ((RequestMessage
->HeaderCount
+ AddNewHeader
) * sizeof(EFI_HTTP_HEADER
));
532 CopyMem ((VOID
*)NewHeaders
, (VOID
*)RequestMessage
->Headers
, RequestMessage
->HeaderCount
* sizeof (EFI_HTTP_HEADER
));
533 if (AddNewHeader
== 0) {
535 // Override content-length to Transfer-Encoding.
537 ContentLengthHeader
= HttpFindHeader (RequestMessage
->HeaderCount
, NewHeaders
, HTTP_HEADER_CONTENT_LENGTH
);
538 ContentLengthHeader
->FieldName
= NULL
;
539 ContentLengthHeader
->FieldValue
= NULL
;
541 ContentLengthHeader
= NewHeaders
+ RequestMessage
->HeaderCount
;
543 HttpSetFieldNameAndValue (ContentLengthHeader
, HTTP_HEADER_TRANSFER_ENCODING
, HTTP_HEADER_TRANSFER_ENCODING_CHUNKED
);
544 HeaderCount
= RequestMessage
->HeaderCount
+ AddNewHeader
;
545 MessageBodyLength
= 0;
547 SentRequestData
= RequestMessage
->Data
.Request
;
550 case HttpIoSendChunkContent
:
553 SentRequestData
= NULL
;
554 if (RequestMessage
->BodyLength
> HTTP_IO_MAX_SEND_PAYLOAD
) {
555 MessageBodyLength
= HTTP_IO_MAX_SEND_PAYLOAD
;
557 MessageBodyLength
= RequestMessage
->BodyLength
;
561 HTTP_IO_CHUNK_SIZE_STRING_LEN
,
564 CHUNKED_TRANSFER_CODING_CR
,
565 CHUNKED_TRANSFER_CODING_LF
567 ChunkLength
= AsciiStrLen (ChunkLengthStr
);
568 MessageBody
= AllocatePool (ChunkLength
+ MessageBodyLength
+ 2);
569 if (MessageBody
== NULL
) {
570 DEBUG((DEBUG_ERROR
, "Not enough memory for chunk transfer\n"));
571 return EFI_OUT_OF_RESOURCES
;
574 // Build up the chunk transfer paylaod.
576 CopyMem (MessageBody
, ChunkLengthStr
, ChunkLength
);
577 CopyMem (MessageBody
+ ChunkLength
, RequestMessage
->Body
, MessageBodyLength
);
578 *(MessageBody
+ ChunkLength
+ MessageBodyLength
) = CHUNKED_TRANSFER_CODING_CR
;
579 *(MessageBody
+ ChunkLength
+ MessageBodyLength
+ 1) = CHUNKED_TRANSFER_CODING_LF
;
581 // Change variables for the next chunk trasnfer.
583 RequestMessage
->BodyLength
-= MessageBodyLength
;
584 RequestMessage
->Body
= (VOID
*)((CHAR8
*)RequestMessage
->Body
+ MessageBodyLength
);
585 MessageBodyLength
+= (ChunkLength
+ 2);
586 if (RequestMessage
->BodyLength
== 0) {
587 *SendChunkProcess
= HttpIoSendChunkEndChunk
;
591 case HttpIoSendChunkEndChunk
:
594 SentRequestData
= NULL
;
597 HTTP_IO_CHUNK_SIZE_STRING_LEN
,
599 CHUNKED_TRANSFER_CODING_CR
,
600 CHUNKED_TRANSFER_CODING_LF
,
601 CHUNKED_TRANSFER_CODING_CR
,
602 CHUNKED_TRANSFER_CODING_LF
604 MessageBody
= AllocatePool (AsciiStrLen(ChunkLengthStr
));
605 if (MessageBody
== NULL
) {
606 DEBUG((DEBUG_ERROR
, "Not enough memory for the end chunk transfer\n"));
607 return EFI_OUT_OF_RESOURCES
;
609 CopyMem (MessageBody
, ChunkLengthStr
, AsciiStrLen (ChunkLengthStr
));
610 MessageBodyLength
= AsciiStrLen (ChunkLengthStr
);
611 *SendChunkProcess
= HttpIoSendChunkFinish
;
615 return EFI_INVALID_PARAMETER
;
618 Status
= HttpIoSendRequest (
626 if (ContentLengthHeader
!= NULL
) {
627 if (ContentLengthHeader
->FieldName
!= NULL
) {
628 FreePool (ContentLengthHeader
->FieldName
);
630 if (ContentLengthHeader
->FieldValue
!= NULL
) {
631 FreePool (ContentLengthHeader
->FieldValue
);
634 if (NewHeaders
!= NULL
) {
635 FreePool (NewHeaders
);
637 if (MessageBody
!= NULL
) {
638 FreePool (MessageBody
);
644 Synchronously receive a HTTP RESPONSE message from the server.
646 @param[in] HttpIo The HttpIo wrapping the HTTP service.
647 @param[in] HeaderCount Number of headers in Headers.
648 @param[in] Headers Array containing list of HTTP headers.
649 @param[out] ChunkListHead A pointer to receive list head
650 of chunked data. Caller has to
651 release memory of ChunkListHead
652 and all list entries.
653 @param[out] ContentLength Total content length
655 @retval EFI_SUCCESS The HTTP chunked transfer is received.
656 @retval EFI_NOT_FOUND No chunked transfer coding header found.
657 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
658 @retval EFI_INVALID_PARAMETER Improper parameters.
659 @retval Others Other errors as indicated.
663 HttpIoGetChunkedTransferContent (
665 IN UINTN HeaderCount
,
666 IN EFI_HTTP_HEADER
*Headers
,
667 OUT LIST_ENTRY
**ChunkListHead
,
668 OUT UINTN
*ContentLength
671 EFI_HTTP_HEADER
*Header
;
672 CHAR8 ChunkSizeAscii
[256];
675 HTTP_IO_RESPONSE_DATA ResponseData
;
677 UINTN MaxTotalLength
;
678 LIST_ENTRY
*HttpChunks
;
679 HTTP_IO_CHUNKS
*ThisChunk
;
680 LIST_ENTRY
*ThisListEntry
;
682 if (ChunkListHead
== NULL
|| ContentLength
== NULL
) {
683 return EFI_INVALID_PARAMETER
;
687 Header
= HttpFindHeader (HeaderCount
, Headers
, HTTP_HEADER_TRANSFER_ENCODING
);
688 if (Header
== NULL
) {
689 return EFI_NOT_FOUND
;
692 if (AsciiStrCmp (Header
->FieldValue
, HTTP_HEADER_TRANSFER_ENCODING_CHUNKED
) != 0) {
693 return EFI_NOT_FOUND
;
696 // Loop to get all chunks.
699 MaxTotalLength
= PcdGet32 (PcdMaxHttpChunkTransfer
);
700 HttpChunks
= (LIST_ENTRY
*)AllocateZeroPool (sizeof (LIST_ENTRY
));
701 if (HttpChunks
== NULL
) {
702 Status
= EFI_OUT_OF_RESOURCES
;
703 goto ExitDeleteChunks
;
705 InitializeListHead (HttpChunks
);
706 DEBUG ((DEBUG_INFO
, " Chunked transfer\n"));
708 ZeroMem((VOID
*)&ResponseData
, sizeof(HTTP_IO_RESPONSE_DATA
));
709 ResponseData
.BodyLength
= HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
;
710 ResponseData
.Body
= ChunkSizeAscii
;
711 Status
= HttpIoRecvResponse (
716 if (EFI_ERROR (Status
)) {
717 goto ExitDeleteChunks
;
720 // Decoding Chunked Transfer Coding.
721 // Only decode chunk-size and last chunk.
723 DEBUG ((DEBUG_INFO
, " Chunk HTTP Response StatusCode - %d\n", ResponseData
.Response
.StatusCode
));
725 // Break if this is last chunk.
727 if (ChunkSizeAscii
[0] == CHUNKED_TRANSFER_CODING_LAST_CHUNK
) {
729 // Check if this is a valid Last-Chunk.
731 if ((ChunkSizeAscii
[1] != CHUNKED_TRANSFER_CODING_CR
) ||
732 (ChunkSizeAscii
[2] != CHUNKED_TRANSFER_CODING_LF
)
734 DEBUG ((DEBUG_ERROR
, " This is an invalid Last-chunk\n"));
735 Status
= EFI_INVALID_PARAMETER
;
736 goto ExitDeleteChunks
;
739 Status
= EFI_SUCCESS
;
740 DEBUG ((DEBUG_INFO
, " Last-chunk\n"));
741 ThisChunk
= (HTTP_IO_CHUNKS
*)AllocateZeroPool (sizeof (HTTP_IO_CHUNKS
));
742 if (ThisChunk
== NULL
) {
743 Status
= EFI_OUT_OF_RESOURCES
;
744 goto ExitDeleteChunks
;
747 InitializeListHead (&ThisChunk
->NextChunk
);
748 ThisChunk
->Length
= ResponseData
.BodyLength
- 1 - 2; // Minus sizeof '0' and CRLF.
749 ThisChunk
->Data
= (CHAR8
*)AllocatePool (ThisChunk
->Length
);
750 if (ThisChunk
->Data
== NULL
) {
751 FreePool ((UINT8
*)ThisChunk
);
752 Status
= EFI_OUT_OF_RESOURCES
;
753 goto ExitDeleteChunks
;
755 CopyMem ((UINT8
*)ThisChunk
->Data
, (UINT8
*)ResponseData
.Body
+ 1, ThisChunk
->Length
);
756 TotalLength
+= ThisChunk
->Length
;
757 InsertTailList (HttpChunks
, &ThisChunk
->NextChunk
);
762 // Get the chunk length
765 while ((ChunkSizeAscii
[Index
] != CHUNKED_TRANSFER_CODING_EXTENSION_SEPARATOR
) &&
766 (ChunkSizeAscii
[Index
] != (CHAR8
)CHUNKED_TRANSFER_CODING_CR
) &&
767 (Index
!= HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
)) {
771 if (Index
== HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
) {
772 Status
= EFI_NOT_FOUND
;
773 goto ExitDeleteChunks
;
775 ChunkSizeAscii
[Index
] = 0;
776 AsciiStrHexToUintnS (ChunkSizeAscii
, NULL
, ContentLength
);
777 DEBUG ((DEBUG_INFO
, " Length of this chunk %d\n", *ContentLength
));
781 ThisChunk
= (HTTP_IO_CHUNKS
*)AllocateZeroPool (sizeof (HTTP_IO_CHUNKS
));
782 if (ThisChunk
== NULL
) {
783 Status
= EFI_OUT_OF_RESOURCES
;
784 goto ExitDeleteChunks
;
786 ResponseData
.BodyLength
= *ContentLength
;
787 ResponseData
.Body
= (CHAR8
*)AllocatePool (*ContentLength
);
788 if (ResponseData
.Body
== NULL
) {
789 FreePool (ThisChunk
);
790 Status
= EFI_OUT_OF_RESOURCES
;
791 goto ExitDeleteChunks
;
793 InitializeListHead (&ThisChunk
->NextChunk
);
794 ThisChunk
->Length
= *ContentLength
;
795 ThisChunk
->Data
= ResponseData
.Body
;
796 InsertTailList (HttpChunks
, &ThisChunk
->NextChunk
);
797 Status
= HttpIoRecvResponse (
802 if (EFI_ERROR (Status
)) {
803 goto ExitDeleteChunks
;
808 ZeroMem((VOID
*)&ResponseData
, sizeof(HTTP_IO_RESPONSE_DATA
));
809 ResponseData
.BodyLength
= 2;
810 ResponseData
.Body
= ChunkSizeAscii
;
811 Status
= HttpIoRecvResponse (
816 if (EFI_ERROR (Status
)) {
817 goto ExitDeleteChunks
;
820 // Verify the end of chunk payload.
822 if ((ChunkSizeAscii
[0] != CHUNKED_TRANSFER_CODING_CR
) ||
823 (ChunkSizeAscii
[1] != CHUNKED_TRANSFER_CODING_LF
)
825 DEBUG ((DEBUG_ERROR
, " This is an invalid End-of-chunk notation.\n"));
826 goto ExitDeleteChunks
;
828 TotalLength
+= *ContentLength
;
829 if (TotalLength
> MaxTotalLength
) {
830 DEBUG ((DEBUG_ERROR
, " Total chunk transfer payload exceeds the size defined by PcdMaxHttpChunkTransfer.\n"));
831 goto ExitDeleteChunks
;
835 *ContentLength
= TotalLength
;
836 *ChunkListHead
= HttpChunks
;
837 DEBUG ((DEBUG_INFO
, " Total of lengh of chunks :%d\n", TotalLength
));
841 if (HttpChunks
!= NULL
) {
842 while (!IsListEmpty(HttpChunks
)) {
843 ThisListEntry
= GetFirstNode (HttpChunks
);
844 RemoveEntryList (ThisListEntry
);
845 ThisChunk
= (HTTP_IO_CHUNKS
*)ThisListEntry
;
846 if (ThisChunk
->Data
!= NULL
) {
847 FreePool (ThisChunk
->Data
);
849 FreePool(ThisListEntry
);
851 FreePool (HttpChunks
);