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
;
193 if (ConfigData
!= NULL
) {
194 if (HttpIo
->IpVersion
== IP_VERSION_4
) {
195 HttpConfigData
.LocalAddressIsIPv6
= FALSE
;
196 HttpConfigData
.HttpVersion
= ConfigData
->Config4
.HttpVersion
;
197 HttpConfigData
.TimeOutMillisec
= ConfigData
->Config4
.RequestTimeOut
;
199 Http4AccessPoint
.UseDefaultAddress
= ConfigData
->Config4
.UseDefaultAddress
;
200 Http4AccessPoint
.LocalPort
= ConfigData
->Config4
.LocalPort
;
201 IP4_COPY_ADDRESS (&Http4AccessPoint
.LocalAddress
, &ConfigData
->Config4
.LocalIp
);
202 IP4_COPY_ADDRESS (&Http4AccessPoint
.LocalSubnet
, &ConfigData
->Config4
.SubnetMask
);
203 HttpConfigData
.AccessPoint
.IPv4Node
= &Http4AccessPoint
;
205 HttpConfigData
.LocalAddressIsIPv6
= TRUE
;
206 HttpConfigData
.HttpVersion
= ConfigData
->Config6
.HttpVersion
;
207 HttpConfigData
.TimeOutMillisec
= ConfigData
->Config6
.RequestTimeOut
;
209 Http6AccessPoint
.LocalPort
= ConfigData
->Config6
.LocalPort
;
210 IP6_COPY_ADDRESS (&Http6AccessPoint
.LocalAddress
, &ConfigData
->Config6
.LocalIp
);
211 HttpConfigData
.AccessPoint
.IPv6Node
= &Http6AccessPoint
;
214 Status
= Http
->Configure (Http
, &HttpConfigData
);
215 if (EFI_ERROR (Status
)) {
221 // Create events for variuos asynchronous operations.
223 Status
= gBS
->CreateEvent (
230 if (EFI_ERROR (Status
)) {
233 HttpIo
->ReqToken
.Event
= Event
;
234 HttpIo
->ReqToken
.Message
= &HttpIo
->ReqMessage
;
236 Status
= gBS
->CreateEvent (
243 if (EFI_ERROR (Status
)) {
246 HttpIo
->RspToken
.Event
= Event
;
247 HttpIo
->RspToken
.Message
= &HttpIo
->RspMessage
;
250 // Create TimeoutEvent for response
252 Status
= gBS
->CreateEvent (
259 if (EFI_ERROR (Status
)) {
262 HttpIo
->TimeoutEvent
= Event
;
266 HttpIoDestroyIo (HttpIo
);
272 Synchronously send a HTTP REQUEST message to the server.
274 @param[in] HttpIo The HttpIo wrapping the HTTP service.
275 @param[in] Request A pointer to storage such data as URL and HTTP method.
276 @param[in] HeaderCount Number of HTTP header structures in Headers list.
277 @param[in] Headers Array containing list of HTTP headers.
278 @param[in] BodyLength Length in bytes of the HTTP body.
279 @param[in] Body Body associated with the HTTP request.
281 @retval EFI_SUCCESS The HTTP request is trasmitted.
282 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
283 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
284 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
285 @retval Others Other errors as indicated.
291 IN EFI_HTTP_REQUEST_DATA
*Request
,
292 IN UINTN HeaderCount
,
293 IN EFI_HTTP_HEADER
*Headers
,
299 EFI_HTTP_PROTOCOL
*Http
;
301 if (HttpIo
== NULL
|| HttpIo
->Http
== NULL
) {
302 return EFI_INVALID_PARAMETER
;
305 HttpIo
->ReqToken
.Status
= EFI_NOT_READY
;
306 HttpIo
->ReqToken
.Message
->Data
.Request
= Request
;
307 HttpIo
->ReqToken
.Message
->HeaderCount
= HeaderCount
;
308 HttpIo
->ReqToken
.Message
->Headers
= Headers
;
309 HttpIo
->ReqToken
.Message
->BodyLength
= BodyLength
;
310 HttpIo
->ReqToken
.Message
->Body
= Body
;
312 if (HttpIo
->Callback
!= NULL
) {
313 Status
= HttpIo
->Callback (
315 HttpIo
->ReqToken
.Message
,
318 if (EFI_ERROR (Status
)) {
324 // Queue the request token to HTTP instances.
327 HttpIo
->IsTxDone
= FALSE
;
328 Status
= Http
->Request (
332 if (EFI_ERROR (Status
)) {
337 // Poll the network until transmit finish.
339 while (!HttpIo
->IsTxDone
) {
343 return HttpIo
->ReqToken
.Status
;
347 Synchronously receive a HTTP RESPONSE message from the server.
349 @param[in] HttpIo The HttpIo wrapping the HTTP service.
350 @param[in] RecvMsgHeader TRUE to receive a new HTTP response (from message header).
351 FALSE to continue receive the previous response message.
352 @param[out] ResponseData Point to a wrapper of the received response data.
354 @retval EFI_SUCCESS The HTTP response is received.
355 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
356 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
357 @retval EFI_DEVICE_ERROR An unexpected network or system error occurred.
358 @retval Others Other errors as indicated.
364 IN BOOLEAN RecvMsgHeader
,
365 OUT HTTP_IO_RESPONSE_DATA
*ResponseData
369 EFI_HTTP_PROTOCOL
*Http
;
371 if (HttpIo
== NULL
|| HttpIo
->Http
== NULL
|| ResponseData
== NULL
) {
372 return EFI_INVALID_PARAMETER
;
376 // Queue the response token to HTTP instances.
378 HttpIo
->RspToken
.Status
= EFI_NOT_READY
;
380 HttpIo
->RspToken
.Message
->Data
.Response
= &ResponseData
->Response
;
382 HttpIo
->RspToken
.Message
->Data
.Response
= NULL
;
384 HttpIo
->RspToken
.Message
->HeaderCount
= 0;
385 HttpIo
->RspToken
.Message
->Headers
= NULL
;
386 HttpIo
->RspToken
.Message
->BodyLength
= ResponseData
->BodyLength
;
387 HttpIo
->RspToken
.Message
->Body
= ResponseData
->Body
;
390 HttpIo
->IsRxDone
= FALSE
;
393 // Start the timer, and wait Timeout seconds to receive the header packet.
395 Status
= gBS
->SetTimer (HttpIo
->TimeoutEvent
, TimerRelative
, HttpIo
->Timeout
* TICKS_PER_MS
);
396 if (EFI_ERROR (Status
)) {
400 Status
= Http
->Response (
405 if (EFI_ERROR (Status
)) {
407 // Remove timeout timer from the event list.
409 gBS
->SetTimer (HttpIo
->TimeoutEvent
, TimerCancel
, 0);
414 // Poll the network until receive finish.
416 while (!HttpIo
->IsRxDone
&& EFI_ERROR (gBS
->CheckEvent (HttpIo
->TimeoutEvent
))) {
421 // Remove timeout timer from the event list.
423 gBS
->SetTimer (HttpIo
->TimeoutEvent
, TimerCancel
, 0);
425 if (!HttpIo
->IsRxDone
) {
427 // Timeout occurs, cancel the response token.
429 Http
->Cancel (Http
, &HttpIo
->RspToken
);
431 Status
= EFI_TIMEOUT
;
435 HttpIo
->IsRxDone
= FALSE
;
438 if ((HttpIo
->Callback
!= NULL
) &&
439 (HttpIo
->RspToken
.Status
== EFI_SUCCESS
|| HttpIo
->RspToken
.Status
== EFI_HTTP_ERROR
)) {
440 Status
= HttpIo
->Callback (
442 HttpIo
->RspToken
.Message
,
445 if (EFI_ERROR (Status
)) {
451 // Store the received data into the wrapper.
453 ResponseData
->Status
= HttpIo
->RspToken
.Status
;
454 ResponseData
->HeaderCount
= HttpIo
->RspToken
.Message
->HeaderCount
;
455 ResponseData
->Headers
= HttpIo
->RspToken
.Message
->Headers
;
456 ResponseData
->BodyLength
= HttpIo
->RspToken
.Message
->BodyLength
;
462 Get the value of the content length if there is a "Content-Length" header.
464 @param[in] HeaderCount Number of HTTP header structures in Headers.
465 @param[in] Headers Array containing list of HTTP headers.
466 @param[out] ContentLength Pointer to save the value of the content length.
468 @retval EFI_SUCCESS Successfully get the content length.
469 @retval EFI_NOT_FOUND No "Content-Length" header in the Headers.
473 HttpIoGetContentLength (
474 IN UINTN HeaderCount
,
475 IN EFI_HTTP_HEADER
*Headers
,
476 OUT UINTN
*ContentLength
479 EFI_HTTP_HEADER
*Header
;
481 Header
= HttpFindHeader (HeaderCount
, Headers
, HTTP_HEADER_CONTENT_LENGTH
);
482 if (Header
== NULL
) {
483 return EFI_NOT_FOUND
;
486 return AsciiStrDecimalToUintnS (Header
->FieldValue
, (CHAR8
**) NULL
, ContentLength
);
489 Send HTTP request in chunks.
491 @param[in] HttpIo The HttpIo wrapping the HTTP service.
492 @param[in] SendChunkProcess Pointer to current chunk process status.
493 @param[in] RequestMessage Request to send.
495 @retval EFI_SUCCESS Successfully to send chunk data according to SendChunkProcess.
496 @retval Other Other errors.
500 HttpIoSendChunkedTransfer (
502 IN HTTP_IO_SEND_CHUNK_PROCESS
*SendChunkProcess
,
503 IN EFI_HTTP_MESSAGE
*RequestMessage
507 EFI_HTTP_HEADER
*NewHeaders
;
508 EFI_HTTP_HEADER
*ContentLengthHeader
;
512 UINTN MessageBodyLength
;
514 CHAR8 ChunkLengthStr
[HTTP_IO_CHUNK_SIZE_STRING_LEN
];
515 EFI_HTTP_REQUEST_DATA
*SentRequestData
;
520 ContentLengthHeader
= NULL
;
521 MessageBodyLength
= 0;
523 switch (*SendChunkProcess
) {
524 case HttpIoSendChunkHeaderZeroContent
:
525 ContentLengthHeader
= HttpFindHeader (RequestMessage
->HeaderCount
, RequestMessage
->Headers
, HTTP_HEADER_CONTENT_LENGTH
);
526 if (ContentLengthHeader
== NULL
) {
530 NewHeaders
= AllocateZeroPool ((RequestMessage
->HeaderCount
+ AddNewHeader
) * sizeof(EFI_HTTP_HEADER
));
531 CopyMem ((VOID
*)NewHeaders
, (VOID
*)RequestMessage
->Headers
, RequestMessage
->HeaderCount
* sizeof (EFI_HTTP_HEADER
));
532 if (AddNewHeader
== 0) {
534 // Override content-length to Transfer-Encoding.
536 ContentLengthHeader
= HttpFindHeader (RequestMessage
->HeaderCount
, NewHeaders
, HTTP_HEADER_CONTENT_LENGTH
);
537 ContentLengthHeader
->FieldName
= NULL
;
538 ContentLengthHeader
->FieldValue
= NULL
;
540 ContentLengthHeader
= NewHeaders
+ RequestMessage
->HeaderCount
;
542 HttpSetFieldNameAndValue (ContentLengthHeader
, HTTP_HEADER_TRANSFER_ENCODING
, HTTP_HEADER_TRANSFER_ENCODING_CHUNKED
);
543 HeaderCount
= RequestMessage
->HeaderCount
+ AddNewHeader
;
544 MessageBodyLength
= 0;
546 SentRequestData
= RequestMessage
->Data
.Request
;
549 case HttpIoSendChunkContent
:
552 SentRequestData
= NULL
;
553 if (RequestMessage
->BodyLength
> HTTP_IO_MAX_SEND_PAYLOAD
) {
554 MessageBodyLength
= HTTP_IO_MAX_SEND_PAYLOAD
;
556 MessageBodyLength
= RequestMessage
->BodyLength
;
560 HTTP_IO_CHUNK_SIZE_STRING_LEN
,
563 CHUNKED_TRANSFER_CODING_CR
,
564 CHUNKED_TRANSFER_CODING_LF
566 ChunkLength
= AsciiStrLen (ChunkLengthStr
);
567 MessageBody
= AllocatePool (ChunkLength
+ MessageBodyLength
+ 2);
568 if (MessageBody
== NULL
) {
569 DEBUG((DEBUG_ERROR
, "Not enough memory for chunk transfer\n"));
570 return EFI_OUT_OF_RESOURCES
;
573 // Build up the chunk transfer paylaod.
575 CopyMem (MessageBody
, ChunkLengthStr
, ChunkLength
);
576 CopyMem (MessageBody
+ ChunkLength
, RequestMessage
->Body
, MessageBodyLength
);
577 *(MessageBody
+ ChunkLength
+ MessageBodyLength
) = CHUNKED_TRANSFER_CODING_CR
;
578 *(MessageBody
+ ChunkLength
+ MessageBodyLength
+ 1) = CHUNKED_TRANSFER_CODING_LF
;
580 // Change variables for the next chunk trasnfer.
582 RequestMessage
->BodyLength
-= MessageBodyLength
;
583 RequestMessage
->Body
= (VOID
*)((CHAR8
*)RequestMessage
->Body
+ MessageBodyLength
);
584 MessageBodyLength
+= (ChunkLength
+ 2);
585 if (RequestMessage
->BodyLength
== 0) {
586 *SendChunkProcess
= HttpIoSendChunkEndChunk
;
590 case HttpIoSendChunkEndChunk
:
593 SentRequestData
= NULL
;
596 HTTP_IO_CHUNK_SIZE_STRING_LEN
,
598 CHUNKED_TRANSFER_CODING_CR
,
599 CHUNKED_TRANSFER_CODING_LF
,
600 CHUNKED_TRANSFER_CODING_CR
,
601 CHUNKED_TRANSFER_CODING_LF
603 MessageBody
= AllocatePool (AsciiStrLen(ChunkLengthStr
));
604 if (MessageBody
== NULL
) {
605 DEBUG((DEBUG_ERROR
, "Not enough memory for the end chunk transfer\n"));
606 return EFI_OUT_OF_RESOURCES
;
608 CopyMem (MessageBody
, ChunkLengthStr
, AsciiStrLen (ChunkLengthStr
));
609 MessageBodyLength
= AsciiStrLen (ChunkLengthStr
);
610 *SendChunkProcess
= HttpIoSendChunkFinish
;
614 return EFI_INVALID_PARAMETER
;
617 Status
= HttpIoSendRequest (
625 if (ContentLengthHeader
!= NULL
) {
626 if (ContentLengthHeader
->FieldName
!= NULL
) {
627 FreePool (ContentLengthHeader
->FieldName
);
629 if (ContentLengthHeader
->FieldValue
!= NULL
) {
630 FreePool (ContentLengthHeader
->FieldValue
);
633 if (NewHeaders
!= NULL
) {
634 FreePool (NewHeaders
);
636 if (MessageBody
!= NULL
) {
637 FreePool (MessageBody
);
643 Synchronously receive a HTTP RESPONSE message from the server.
645 @param[in] HttpIo The HttpIo wrapping the HTTP service.
646 @param[in] HeaderCount Number of headers in Headers.
647 @param[in] Headers Array containing list of HTTP headers.
648 @param[out] ChunkListHead A pointer to receive list head
649 of chunked data. Caller has to
650 release memory of ChunkListHead
651 and all list entries.
652 @param[out] ContentLength Total content length
654 @retval EFI_SUCCESS The HTTP chunked transfer is received.
655 @retval EFI_NOT_FOUND No chunked transfer coding header found.
656 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
657 @retval EFI_INVALID_PARAMETER Improper parameters.
658 @retval Others Other errors as indicated.
662 HttpIoGetChunkedTransferContent (
664 IN UINTN HeaderCount
,
665 IN EFI_HTTP_HEADER
*Headers
,
666 OUT LIST_ENTRY
**ChunkListHead
,
667 OUT UINTN
*ContentLength
670 EFI_HTTP_HEADER
*Header
;
671 CHAR8 ChunkSizeAscii
[256];
674 HTTP_IO_RESPONSE_DATA ResponseData
;
676 UINTN MaxTotalLength
;
677 LIST_ENTRY
*HttpChunks
;
678 HTTP_IO_CHUNKS
*ThisChunk
;
679 LIST_ENTRY
*ThisListEntry
;
681 if (ChunkListHead
== NULL
|| ContentLength
== NULL
) {
682 return EFI_INVALID_PARAMETER
;
686 Header
= HttpFindHeader (HeaderCount
, Headers
, HTTP_HEADER_TRANSFER_ENCODING
);
687 if (Header
== NULL
) {
688 return EFI_NOT_FOUND
;
691 if (AsciiStrCmp (Header
->FieldValue
, HTTP_HEADER_TRANSFER_ENCODING_CHUNKED
) != 0) {
692 return EFI_NOT_FOUND
;
695 // Loop to get all chunks.
698 MaxTotalLength
= PcdGet32 (PcdMaxHttpChunkTransfer
);
699 HttpChunks
= (LIST_ENTRY
*)AllocateZeroPool (sizeof (LIST_ENTRY
));
700 if (HttpChunks
== NULL
) {
701 Status
= EFI_OUT_OF_RESOURCES
;
702 goto ExitDeleteChunks
;
704 InitializeListHead (HttpChunks
);
705 DEBUG ((DEBUG_INFO
, " Chunked transfer\n"));
707 ZeroMem((VOID
*)&ResponseData
, sizeof(HTTP_IO_RESPONSE_DATA
));
708 ResponseData
.BodyLength
= HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
;
709 ResponseData
.Body
= ChunkSizeAscii
;
710 Status
= HttpIoRecvResponse (
715 if (EFI_ERROR (Status
)) {
716 goto ExitDeleteChunks
;
719 // Decoding Chunked Transfer Coding.
720 // Only decode chunk-size and last chunk.
722 DEBUG ((DEBUG_INFO
, " Chunk HTTP Response StatusCode - %d\n", ResponseData
.Response
.StatusCode
));
724 // Break if this is last chunk.
726 if (ChunkSizeAscii
[0] == CHUNKED_TRANSFER_CODING_LAST_CHUNK
) {
728 // Check if this is a valid Last-Chunk.
730 if ((ChunkSizeAscii
[1] != CHUNKED_TRANSFER_CODING_CR
) ||
731 (ChunkSizeAscii
[2] != CHUNKED_TRANSFER_CODING_LF
)
733 DEBUG ((DEBUG_ERROR
, " This is an invalid Last-chunk\n"));
734 Status
= EFI_INVALID_PARAMETER
;
735 goto ExitDeleteChunks
;
738 Status
= EFI_SUCCESS
;
739 DEBUG ((DEBUG_INFO
, " Last-chunk\n"));
740 ThisChunk
= (HTTP_IO_CHUNKS
*)AllocateZeroPool (sizeof (HTTP_IO_CHUNKS
));
741 if (ThisChunk
== NULL
) {
742 Status
= EFI_OUT_OF_RESOURCES
;
743 goto ExitDeleteChunks
;
746 InitializeListHead (&ThisChunk
->NextChunk
);
747 ThisChunk
->Length
= ResponseData
.BodyLength
- 1 - 2; // Minus sizeof '0' and CRLF.
748 ThisChunk
->Data
= (CHAR8
*)AllocatePool (ThisChunk
->Length
);
749 if (ThisChunk
->Data
== NULL
) {
750 FreePool ((UINT8
*)ThisChunk
);
751 Status
= EFI_OUT_OF_RESOURCES
;
752 goto ExitDeleteChunks
;
754 CopyMem ((UINT8
*)ThisChunk
->Data
, (UINT8
*)ResponseData
.Body
+ 1, ThisChunk
->Length
);
755 TotalLength
+= ThisChunk
->Length
;
756 InsertTailList (HttpChunks
, &ThisChunk
->NextChunk
);
761 // Get the chunk length
764 while ((ChunkSizeAscii
[Index
] != CHUNKED_TRANSFER_CODING_EXTENSION_SEPARATOR
) &&
765 (ChunkSizeAscii
[Index
] != (CHAR8
)CHUNKED_TRANSFER_CODING_CR
) &&
766 (Index
!= HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
)) {
770 if (Index
== HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
) {
771 Status
= EFI_NOT_FOUND
;
772 goto ExitDeleteChunks
;
774 ChunkSizeAscii
[Index
] = 0;
775 AsciiStrHexToUintnS (ChunkSizeAscii
, NULL
, ContentLength
);
776 DEBUG ((DEBUG_INFO
, " Length of this chunk %d\n", *ContentLength
));
780 ThisChunk
= (HTTP_IO_CHUNKS
*)AllocateZeroPool (sizeof (HTTP_IO_CHUNKS
));
781 if (ThisChunk
== NULL
) {
782 Status
= EFI_OUT_OF_RESOURCES
;
783 goto ExitDeleteChunks
;
785 ResponseData
.BodyLength
= *ContentLength
;
786 ResponseData
.Body
= (CHAR8
*)AllocatePool (*ContentLength
);
787 if (ResponseData
.Body
== NULL
) {
788 FreePool (ThisChunk
);
789 Status
= EFI_OUT_OF_RESOURCES
;
790 goto ExitDeleteChunks
;
792 InitializeListHead (&ThisChunk
->NextChunk
);
793 ThisChunk
->Length
= *ContentLength
;
794 ThisChunk
->Data
= ResponseData
.Body
;
795 InsertTailList (HttpChunks
, &ThisChunk
->NextChunk
);
796 Status
= HttpIoRecvResponse (
801 if (EFI_ERROR (Status
)) {
802 goto ExitDeleteChunks
;
807 ZeroMem((VOID
*)&ResponseData
, sizeof(HTTP_IO_RESPONSE_DATA
));
808 ResponseData
.BodyLength
= 2;
809 ResponseData
.Body
= ChunkSizeAscii
;
810 Status
= HttpIoRecvResponse (
815 if (EFI_ERROR (Status
)) {
816 goto ExitDeleteChunks
;
819 // Verify the end of chunk payload.
821 if ((ChunkSizeAscii
[0] != CHUNKED_TRANSFER_CODING_CR
) ||
822 (ChunkSizeAscii
[1] != CHUNKED_TRANSFER_CODING_LF
)
824 DEBUG ((DEBUG_ERROR
, " This is an invalid End-of-chunk notation.\n"));
825 goto ExitDeleteChunks
;
827 TotalLength
+= *ContentLength
;
828 if (TotalLength
> MaxTotalLength
) {
829 DEBUG ((DEBUG_ERROR
, " Total chunk transfer payload exceeds the size defined by PcdMaxHttpChunkTransfer.\n"));
830 goto ExitDeleteChunks
;
834 *ContentLength
= TotalLength
;
835 *ChunkListHead
= HttpChunks
;
836 DEBUG ((DEBUG_INFO
, " Total of lengh of chunks :%d\n", TotalLength
));
840 if (HttpChunks
!= NULL
) {
841 while (!IsListEmpty(HttpChunks
)) {
842 ThisListEntry
= GetFirstNode (HttpChunks
);
843 RemoveEntryList (ThisListEntry
);
844 ThisChunk
= (HTTP_IO_CHUNKS
*)ThisListEntry
;
845 if (ThisChunk
->Data
!= NULL
) {
846 FreePool (ThisChunk
->Data
);
848 FreePool(ThisListEntry
);
850 FreePool (HttpChunks
);