[edk2-devel] [DxeHttpIoLib PATCH V2 1/3] NetworkPkg/Library: Implementation of Http IO Helper Library
Abner Chang
abner.chang at hpe.com
Tue Nov 3 06:15:40 UTC 2020
Ok. I created a PCD under NetworkPkg for the maximum size of HTTP chunk transfer payload. The default value is set to 12 MB as the hex value looks nicer :).
V5 patch sent.
Thanks
Abner
> -----Original Message-----
> From: Rabeda, Maciej [mailto:maciej.rabeda at linux.intel.com]
> Sent: Monday, November 2, 2020 10:50 PM
> To: devel at edk2.groups.io; Chang, Abner (HPS SW/FW Technologist)
> <abner.chang at hpe.com>
> Cc: Jiaxin Wu <jiaxin.wu at intel.com>; Siyuan Fu <siyuan.fu at intel.com>;
> Wang, Nickle (HPS SW) <nickle.wang at hpe.com>
> Subject: Re: [edk2-devel] [DxeHttpIoLib PATCH V2 1/3] NetworkPkg/Library:
> Implementation of Http IO Helper Library
>
>
>
> On 02-Nov-20 15:14, Abner Chang wrote:
> >
> >> -----Original Message-----
> >> From: Rabeda, Maciej [mailto:maciej.rabeda at linux.intel.com]
> >> Sent: Monday, November 2, 2020 8:50 PM
> >> To: devel at edk2.groups.io; Chang, Abner (HPS SW/FW Technologist)
> >> <abner.chang at hpe.com>
> >> Cc: Jiaxin Wu <jiaxin.wu at intel.com>; Siyuan Fu <siyuan.fu at intel.com>;
> >> Wang, Nickle (HPS SW) <nickle.wang at hpe.com>
> >> Subject: Re: [edk2-devel] [DxeHttpIoLib PATCH V2 1/3]
> NetworkPkg/Library:
> >> Implementation of Http IO Helper Library
> >>
> >> Hi Abner,
> >>
> >> Comments inline.
> >>
> >> Thanks,
> >> Maciej
> >>
> >> On 29-Oct-20 07:11, Abner Chang wrote:
> >>>> -----Original Message-----
> >>>> From: Rabeda, Maciej [mailto:maciej.rabeda at linux.intel.com]
> >>>> Sent: Thursday, October 29, 2020 2:28 AM
> >>>> To: devel at edk2.groups.io; Chang, Abner (HPS SW/FW Technologist)
> >>>> <abner.chang at hpe.com>
> >>>> Cc: Jiaxin Wu <jiaxin.wu at intel.com>; Siyuan Fu <siyuan.fu at intel.com>;
> >>>> Wang, Nickle (HPS SW) <nickle.wang at hpe.com>
> >>>> Subject: Re: [edk2-devel] [DxeHttpIoLib PATCH V2 1/3]
> >> NetworkPkg/Library:
> >>>> Implementation of Http IO Helper Library
> >>>>
> >>>> Thanks for patching spelling problems in MdePkg header.
> >>>> I will send more comments on v3. Added one here regarding chunk
> >> transfer
> >>>> security.
> >>>>
> >>>> Thanks,
> >>>> Maciej
> >>>>
> >>>> On 26-Oct-20 07:53, Abner Chang wrote:
> >>>>> Thanks for reviewing this Maciej.
> >>>>>
> >>>>> Most of comments are addressed. I also submitted a BZ for the wrong
> >>>> spelling of CHUNK_TRNASFER_*, the patch is already sent.
> >>>>> V3 of this patch set is also sent to the mailing list.
> >>>>>
> >>>>> Other feedbacks are in below,
> >>>>>
> >>>>>> -----Original Message-----
> >>>>>> From: Rabeda, Maciej [mailto:maciej.rabeda at linux.intel.com]
> >>>>>> Sent: Saturday, October 24, 2020 12:25 AM
> >>>>>> To: devel at edk2.groups.io; Chang, Abner (HPS SW/FW Technologist)
> >>>>>> <abner.chang at hpe.com>
> >>>>>> Cc: Jiaxin Wu <jiaxin.wu at intel.com>; Siyuan Fu
> <siyuan.fu at intel.com>;
> >>>>>> Wang, Nickle (HPS SW) <nickle.wang at hpe.com>
> >>>>>> Subject: Re: [edk2-devel] [DxeHttpIoLib PATCH V2 1/3]
> >>>> NetworkPkg/Library:
> >>>>>> Implementation of Http IO Helper Library
> >>>>>>
> >>>>>> Hi Abner,
> >>>>>>
> >>>>>> I understand the concept of moving HTTP I/O layer outside
> >> HttpBootDxe
> >>>> and
> >>>>>> into a separate library and I approve it.
> >>>>>> However, there are some things that have to
> >> addressed/fixed/explained
> >>>>>> here.
> >>>>>> See comments within the patch.
> >>>>>>
> >>>>>> On 20-Oct-20 04:38, Abner Chang wrote:
> >>>>>>> Add HTTP IO helper library which could be sued by HTTP
> applications
> >>>>>>> such as HTTP Boot, Redfish HTTP REST EX driver instance and etc.
> >>>>>>>
> >>>>>>> Signed-off-by: Abner Chang <abner.chang at hpe.com>
> >>>>>>>
> >>>>>>> Cc: Maciej Rabeda <maciej.rabeda at linux.intel.com>
> >>>>>>> Cc: Jiaxin Wu <jiaxin.wu at intel.com>
> >>>>>>> Cc: Siyuan Fu <siyuan.fu at intel.com>
> >>>>>>> Cc: Nickle Wang <nickle.wang at hpe.com>
> >>>>>>> ---
> >>>>>>> NetworkPkg/Include/Library/HttpIoLib.h | 328 +++++++
> >>>>>>> .../Library/DxeHttpIoLib/DxeHttpIoLib.c | 809
> >>>> ++++++++++++++++++
> >>>>>>> .../Library/DxeHttpIoLib/DxeHttpIoLib.inf | 43 +
> >>>>>>> .../Library/DxeHttpIoLib/DxeHttpIoLib.uni | 13 +
> >>>>>>> 4 files changed, 1193 insertions(+)
> >>>>>>> create mode 100644 NetworkPkg/Include/Library/HttpIoLib.h
> >>>>>>> create mode 100644
> >> NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c
> >>>>>>> create mode 100644
> >>>> NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf
> >>>>>>> create mode 100644
> >>>> NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni
> >>>>>>> diff --git a/NetworkPkg/Include/Library/HttpIoLib.h
> >>>>>>> b/NetworkPkg/Include/Library/HttpIoLib.h
> >>>>>>> new file mode 100644
> >>>>>>> index 0000000000..8f3804ca42
> >>>>>>> --- /dev/null
> >>>>>>> +++ b/NetworkPkg/Include/Library/HttpIoLib.h
> >>>>>>> @@ -0,0 +1,328 @@
> >>>>>>> +/** @file
> >>>>>>> + HttpIoLib.h.
> >>>>>>> +
> >>>>>>> +(C) Copyright 2020 Hewlett-Packard Development Company,
> >> L.P.<BR>
> >>>>>>> +SPDX-License-Identifier: BSD-2-Clause-Patent
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +
> >>>>>>> +#ifndef HTTP_IO_LIB_H_
> >>>>>>> +#define HTTP_IO_LIB_H_
> >>>>>>> +
> >>>>>>> +#include <IndustryStandard/Http11.h>
> >>>>>>> +
> >>>>>>> +#include <Library/DpcLib.h>
> >>>>>>> +#include <Library/HttpLib.h>
> >>>>>>> +#include <Library/NetLib.h>
> >>>>>>> +
> >>>>>>> +#define HTTP_IO_MAX_SEND_PAYLOAD 1024
> >>>>>>> +#define HTTP_IO_CHUNK_SIZE_STRING_LEN 50
> >>>>>>> +#define HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH
> >> 256
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// HTTP_IO_CALLBACK_EVENT
> >>>>>>> +///
> >>>>>>> +typedef enum {
> >>>>>>> + HttpIoRequest,
> >>>>>>> + HttpIoResponse
> >>>>>>> +} HTTP_IO_CALLBACK_EVENT;
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + HttpIo Callback function which will be invoked when specified
> >>>>>> HTTP_IO_CALLBACK_EVENT happened.
> >>>>>>> +
> >>>>>>> + @param[in] EventType Indicate the Event type that occurs in
> >> the
> >>>>>> current callback.
> >>>>>>> + @param[in] Message HTTP message which will be send to,
> or
> >> just
> >>>>>> received from HTTP server.
> >>>>>>> + @param[in] Context The Callback Context pointer.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS Tells the HttpIo to continue the HTTP
> >>>> process.
> >>>>>>> + @retval Others Tells the HttpIo to abort the current HTTP
> >>>> process.
> >>>>>>> +**/
> >>>>>>> +typedef
> >>>>>>> +EFI_STATUS
> >>>>>>> +(EFIAPI * HTTP_IO_CALLBACK) (
> >>>>>>> + IN HTTP_IO_CALLBACK_EVENT EventType,
> >>>>>>> + IN EFI_HTTP_MESSAGE *Message,
> >>>>>>> + IN VOID *Context
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// A wrapper structure to hold the received HTTP response data.
> >>>>>>> +///
> >>>>>>> +typedef struct {
> >>>>>>> + EFI_HTTP_RESPONSE_DATA Response;
> >>>>>>> + UINTN HeaderCount;
> >>>>>>> + EFI_HTTP_HEADER *Headers;
> >>>>>>> + UINTN BodyLength;
> >>>>>>> + CHAR8 *Body;
> >>>>>>> + EFI_STATUS Status;
> >>>>>>> +} HTTP_IO_RESPONSE_DATA;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// HTTP_IO configuration data for IPv4 /// typedef struct {
> >>>>>>> + EFI_HTTP_VERSION HttpVersion;
> >>>>>>> + UINT32 RequestTimeOut; ///< In milliseconds.
> >>>>>>> + UINT32 ResponseTimeOut; ///< In milliseconds.
> >>>>>>> + BOOLEAN UseDefaultAddress;
> >>>>>>> + EFI_IPv4_ADDRESS LocalIp;
> >>>>>>> + EFI_IPv4_ADDRESS SubnetMask;
> >>>>>>> + UINT16 LocalPort;
> >>>>>>> +} HTTP4_IO_CONFIG_DATA;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// HTTP_IO configuration data for IPv6 /// typedef struct {
> >>>>>>> + EFI_HTTP_VERSION HttpVersion;
> >>>>>>> + UINT32 RequestTimeOut; ///< In milliseconds.
> >>>>>>> + BOOLEAN UseDefaultAddress;
> >>>>>>> + EFI_IPv6_ADDRESS LocalIp;
> >>>>>>> + UINT16 LocalPort;
> >>>>>>> +} HTTP6_IO_CONFIG_DATA;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// HTTP_IO configuration
> >>>>>>> +///
> >>>>>>> +typedef union {
> >>>>>>> + HTTP4_IO_CONFIG_DATA Config4;
> >>>>>>> + HTTP6_IO_CONFIG_DATA Config6;
> >>>>>>> +} HTTP_IO_CONFIG_DATA;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// HTTP_IO wrapper of the EFI HTTP service.
> >>>>>>> +///
> >>>>>>> +typedef struct {
> >>>>>>> + UINT8 IpVersion;
> >>>>>>> + EFI_HANDLE Image;
> >>>>>>> + EFI_HANDLE Controller;
> >>>>>>> + EFI_HANDLE Handle;
> >>>>>>> +
> >>>>>>> + EFI_HTTP_PROTOCOL *Http;
> >>>>>>> +
> >>>>>>> + HTTP_IO_CALLBACK Callback;
> >>>>>>> + VOID *Context;
> >>>>>>> +
> >>>>>>> + EFI_HTTP_TOKEN ReqToken;
> >>>>>>> + EFI_HTTP_MESSAGE ReqMessage;
> >>>>>>> + EFI_HTTP_TOKEN RspToken;
> >>>>>>> + EFI_HTTP_MESSAGE RspMessage;
> >>>>>>> +
> >>>>>>> + BOOLEAN IsTxDone;
> >>>>>>> + BOOLEAN IsRxDone;
> >>>>>>> +
> >>>>>>> + EFI_EVENT TimeoutEvent;
> >>>>>>> + UINT32 Timeout;
> >>>>>>> +} HTTP_IO;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// Process code of HTTP chunk transfer.
> >>>>>>> +///
> >>>>>>> +typedef enum {
> >>>>>>> + HttpIoSendChunkNone = 0,
> >>>>>>> + HttpIoSendChunkHeaderZeroContent,
> >>>>>>> + HttpIoSendChunkContent,
> >>>>>>> + HttpIoSendChunkEndChunk,
> >>>>>>> + HttpIoSendChunkFinish
> >>>>>>> +} HTTP_IO_SEND_CHUNK_PROCESS;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// Process code of HTTP non chunk transfer.
> >>>>>>> +///
> >>>>>>> +typedef enum {
> >>>>>>> + HttpIoSendNonChunkNone = 0,
> >>>>>>> + HttpIoSendNonChunkHeaderZeroContent,
> >>>>>>> + HttpIoSendNonChunkContent,
> >>>>>>> + HttpIoSendNonChunkFinish
> >>>>>>> +} HTTP_IO_SEND_NON_CHUNK_PROCESS;
> >>>>>>> +
> >>>>>>> +///
> >>>>>>> +/// Chunk links for HTTP chunked transfer coding.
> >>>>>>> +///
> >>>>>>> +typedef struct {
> >>>>>>> + LIST_ENTRY NextChunk;
> >>>>>>> + UINTN Length;
> >>>>>>> + CHAR8 *Data;
> >>>>>>> +} HTTP_IO_CHUNKS;
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Notify the callback function when an event is triggered.
> >>>>>>> +
> >>>>>>> + @param[in] Context The opaque parameter to the function.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +VOID
> >>>>>>> +EFIAPI
> >>>>>>> +HttpIoNotifyDpc (
> >>>>>>> + IN VOID *Context
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.
> >>>>>>> +
> >>>>>>> + @param[in] Event The event signaled.
> >>>>>>> + @param[in] Context The opaque parameter to the
> function.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +VOID
> >>>>>>> +EFIAPI
> >>>>>>> +HttpIoNotify (
> >>>>>>> + IN EFI_EVENT Event,
> >>>>>>> + IN VOID *Context
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Destroy the HTTP_IO and release the resources.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HTTP_IO which wraps the HTTP
> service
> >> to
> >>>> be
> >>>>>> destroyed.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +VOID
> >>>>>>> +HttpIoDestroyIo (
> >>>>>>> + IN HTTP_IO *HttpIo
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Create a HTTP_IO to access the HTTP service. It will create and
> >>>>>>> +configure
> >>>>>>> + a HTTP child handle.
> >>>>>>> +
> >>>>>>> + @param[in] Image The handle of the driver image.
> >>>>>>> + @param[in] Controller The handle of the controller.
> >>>>>>> + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
> >>>>>>> + @param[in] ConfigData The HTTP_IO configuration data.
> >>>>>>> + @param[in] Callback Callback function which will be invoked
> >> when
> >>>>>> specified
> >>>>>>> + HTTP_IO_CALLBACK_EVENT happened.
> >>>>>>> + @param[in] Context The Context data which will be passed
> to
> >> the
> >>>>>> Callback function.
> >>>>>>> + @param[out] HttpIo The HTTP_IO.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP_IO is created and
> configured.
> >>>>>>> + @retval EFI_INVALID_PARAMETER One or more parameters are
> >>>> invalid.
> >>>>>>> + @retval EFI_UNSUPPORTED One or more of the control
> options
> >>>> are
> >>>>>> not
> >>>>>>> + supported in the implementation.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval Others Failed to create the HTTP_IO or configure
> it.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoCreateIo (
> >>>>>>> + IN EFI_HANDLE Image,
> >>>>>>> + IN EFI_HANDLE Controller,
> >>>>>>> + IN UINT8 IpVersion,
> >>>>>>> + IN HTTP_IO_CONFIG_DATA *ConfigData,
> >>>>>>> + IN HTTP_IO_CALLBACK Callback,
> >>>>>>> + IN VOID *Context,
> >>>>>>> + OUT HTTP_IO *HttpIo
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Synchronously send a HTTP REQUEST message to the server.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] Request A pointer to storage such data as URL
> >> and
> >>>>>> HTTP method.
> >>>>>>> + @param[in] HeaderCount Number of HTTP header structures
> in
> >>>>>> Headers list.
> >>>>>>> + @param[in] Headers Array containing list of HTTP headers.
> >>>>>>> + @param[in] BodyLength Length in bytes of the HTTP body.
> >>>>>>> + @param[in] Body Body associated with the HTTP request.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP request is transmitted.
> >>>>>>> + @retval EFI_INVALID_PARAMETER One or more parameters are
> >>>> invalid.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval EFI_DEVICE_ERROR An unexpected network or
> system
> >>>> error
> >>>>>> occurred.
> >>>>>>> + @retval Others Other errors as indicated.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoSendRequest (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN EFI_HTTP_REQUEST_DATA *Request, OPTIONAL
> >>>>>>> + IN UINTN HeaderCount,
> >>>>>>> + IN EFI_HTTP_HEADER *Headers, OPTIONAL
> >>>>>>> + IN UINTN BodyLength,
> >>>>>>> + IN VOID *Body OPTIONAL
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Synchronously receive a HTTP RESPONSE message from the
> server.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] RecvMsgHeader TRUE to receive a new HTTP
> >> response
> >>>>>> (from message header).
> >>>>>>> + FALSE to continue receive the previous response
> >>>> message.
> >>>>>>> + @param[out] ResponseData Point to a wrapper of the
> received
> >>>>>> response data.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP response is received.
> >>>>>>> + @retval EFI_INVALID_PARAMETER One or more parameters are
> >>>> invalid.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval EFI_DEVICE_ERROR An unexpected network or
> system
> >>>> error
> >>>>>> occurred.
> >>>>>>> + @retval Others Other errors as indicated.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoRecvResponse (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN BOOLEAN RecvMsgHeader,
> >>>>>>> + OUT HTTP_IO_RESPONSE_DATA *ResponseData
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Get the value of the content length if there is a "Content-
> Length"
> >>>> header.
> >>>>>>> +
> >>>>>>> + @param[in] HeaderCount Number of HTTP header
> structures
> >> in
> >>>>>> Headers.
> >>>>>>> + @param[in] Headers Array containing list of HTTP headers.
> >>>>>>> + @param[out] ContentLength Pointer to save the value of the
> >>>> content
> >>>>>> length.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS Successfully get the content length.
> >>>>>>> + @retval EFI_NOT_FOUND No "Content-Length" header in
> the
> >>>>>> Headers.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoGetContentLength (
> >>>>>>> + IN UINTN HeaderCount,
> >>>>>>> + IN EFI_HTTP_HEADER *Headers,
> >>>>>>> + OUT UINTN *ContentLength
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Synchronously receive a HTTP RESPONSE message from the
> server.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] HeaderCount Number of headers in Headers.
> >>>>>>> + @param[in] Headers Array containing list of HTTP headers.
> >>>>>>> + @param[out] ChunkListHead A pointer to receivce list head of
> >>>> chunked
> >>>>>> data.
> >>>>>>> + Caller has to release memory of ChunkListHead
> >>>>>>> + and all list entries.
> >>>>>>> + @param[out] ContentLength Total content length
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP chunked transfer is
> received.
> >>>>>>> + @retval EFI_NOT_FOUND No chunked transfer coding
> header
> >>>> found.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval EFI_INVALID_PARAMETER Improper parameters.
> >>>>>>> + @retval Others Other errors as indicated.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoGetChunkedTransferContent (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN UINTN HeaderCount,
> >>>>>>> + IN EFI_HTTP_HEADER *Headers,
> >>>>>>> + OUT LIST_ENTRY **ChunkListHead,
> >>>>>>> + OUT UINTN *ContentLength
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Send HTTP request in chunks.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] SendChunkProcess Pointer to current chunk
> process
> >>>>>> status.
> >>>>>>> + @param[out] RequestMessage Request to send.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS Successfully to send chunk data
> >> according
> >>>> to
> >>>>>> SendChunkProcess.
> >>>>>>> + @retval Other Other errors.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoSendChunkedTransfer (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN HTTP_IO_SEND_CHUNK_PROCESS *SendChunkProcess,
> >>>>>>> + IN EFI_HTTP_MESSAGE *RequestMessage
> >>>>>>> +);
> >>>>>>> +#endif
> >>>>>>> diff --git a/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c
> >>>>>>> b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c
> >>>>>>> new file mode 100644
> >>>>>>> index 0000000000..fbce86ea5c
> >>>>>>> --- /dev/null
> >>>>>>> +++ b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.c
> >>>>>>> @@ -0,0 +1,809 @@
> >>>>>>> +/** @file
> >>>>>>> + Http IO Helper Library.
> >>>>>>> +
> >>>>>>> + (C) Copyright 2020 Hewlett-Packard Development Company,
> >> L.P.<BR>
> >>>>>>> + SPDX-License-Identifier: BSD-2-Clause-Patent **/
> >>>>>>> +
> >>>>>>> +#include <Uefi.h>
> >>>>>>> +
> >>>>>>> +#include <Protocol/Http.h>
> >>>>>>> +
> >>>>>>> +#include <Library/BaseLib.h>
> >>>>>>> +#include <Library/BaseMemoryLib.h>
> >>>>>>> +#include <Library/DebugLib.h>
> >>>>>>> +#include <Library/HttpIoLib.h>
> >>>>>>> +#include <Library/MemoryAllocationLib.h> #include
> >>>>>>> +<Library/PrintLib.h> #include
> <Library/UefiBootServicesTableLib.h>
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Notify the callback function when an event is triggered.
> >>>>>>> +
> >>>>>>> + @param[in] Context The opaque parameter to the function.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +VOID
> >>>>>>> +EFIAPI
> >>>>>>> +HttpIoNotifyDpc (
> >>>>>>> + IN VOID *Context
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + *((BOOLEAN *) Context) = TRUE;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK.
> >>>>>>> +
> >>>>>>> + @param[in] Event The event signaled.
> >>>>>>> + @param[in] Context The opaque parameter to the
> function.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +VOID
> >>>>>>> +EFIAPI
> >>>>>>> +HttpIoNotify (
> >>>>>>> + IN EFI_EVENT Event,
> >>>>>>> + IN VOID *Context
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + //
> >>>>>>> + // Request HttpIoNotifyDpc as a DPC at TPL_CALLBACK
> >>>>>>> + //
> >>>>>>> + QueueDpc (TPL_CALLBACK, HttpIoNotifyDpc, Context); }
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Destroy the HTTP_IO and release the resources.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HTTP_IO which wraps the HTTP
> service
> >> to
> >>>> be
> >>>>>> destroyed.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +VOID
> >>>>>>> +HttpIoDestroyIo (
> >>>>>>> + IN HTTP_IO *HttpIo
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + EFI_HTTP_PROTOCOL *Http;
> >>>>>>> + EFI_EVENT Event;
> >>>>>>> +
> >>>>>>> + if (HttpIo == NULL) {
> >>>>>>> + return;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Event = HttpIo->ReqToken.Event;
> >>>>>>> + if (Event != NULL) {
> >>>>>>> + gBS->CloseEvent (Event);
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Event = HttpIo->RspToken.Event;
> >>>>>>> + if (Event != NULL) {
> >>>>>>> + gBS->CloseEvent (Event);
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Event = HttpIo->TimeoutEvent;
> >>>>>>> + if (Event != NULL) {
> >>>>>>> + gBS->CloseEvent (Event);
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Http = HttpIo->Http;
> >>>>>>> + if (Http != NULL) {
> >>>>>>> + Http->Configure (Http, NULL);
> >>>>>>> + gBS->CloseProtocol (
> >>>>>>> + HttpIo->Handle,
> >>>>>>> + &gEfiHttpProtocolGuid,
> >>>>>>> + HttpIo->Image,
> >>>>>>> + HttpIo->Controller
> >>>>>>> + );
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + NetLibDestroyServiceChild (
> >>>>>>> + HttpIo->Controller,
> >>>>>>> + HttpIo->Image,
> >>>>>>> + &gEfiHttpServiceBindingProtocolGuid,
> >>>>>>> + HttpIo->Handle
> >>>>>>> + );
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Create a HTTP_IO to access the HTTP service. It will create and
> >>>>>>> +configure
> >>>>>>> + a HTTP child handle.
> >>>>>>> +
> >>>>>>> + @param[in] Image The handle of the driver image.
> >>>>>>> + @param[in] Controller The handle of the controller.
> >>>>>>> + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
> >>>>>>> + @param[in] ConfigData The HTTP_IO configuration data ,
> >>>>>>> + NULL means not to configure the HTTP child.
> >>>>>>> + @param[in] Callback Callback function which will be invoked
> >> when
> >>>>>> specified
> >>>>>>> + HTTP_IO_CALLBACK_EVENT happened.
> >>>>>>> + @param[in] Context The Context data which will be passed
> to
> >> the
> >>>>>> Callback function.
> >>>>>>> + @param[out] HttpIo The HTTP_IO.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP_IO is created and
> configured.
> >>>>>>> + @retval EFI_INVALID_PARAMETER One or more parameters are
> >>>> invalid.
> >>>>>>> + @retval EFI_UNSUPPORTED One or more of the control
> options
> >>>> are
> >>>>>> not
> >>>>>>> + supported in the implementation.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval Others Failed to create the HTTP_IO or configure
> it.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoCreateIo (
> >>>>>>> + IN EFI_HANDLE Image,
> >>>>>>> + IN EFI_HANDLE Controller,
> >>>>>>> + IN UINT8 IpVersion,
> >>>>>>> + IN HTTP_IO_CONFIG_DATA *ConfigData, OPTIONAL
> >>>>>>> + IN HTTP_IO_CALLBACK Callback,
> >>>>>>> + IN VOID *Context,
> >>>>>>> + OUT HTTP_IO *HttpIo
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + EFI_STATUS Status;
> >>>>>>> + EFI_HTTP_CONFIG_DATA HttpConfigData;
> >>>>>>> + EFI_HTTPv4_ACCESS_POINT Http4AccessPoint;
> >>>>>>> + EFI_HTTPv6_ACCESS_POINT Http6AccessPoint;
> >>>>>>> + EFI_HTTP_PROTOCOL *Http;
> >>>>>>> + EFI_EVENT Event;
> >>>>>>> +
> >>>>>>> + if ((Image == NULL) || (Controller == NULL) || (HttpIo == NULL))
> {
> >>>>>>> + return EFI_INVALID_PARAMETER;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + if (IpVersion != IP_VERSION_4 && IpVersion != IP_VERSION_6) {
> >>>>>>> + return EFI_UNSUPPORTED;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + ZeroMem (HttpIo, sizeof (HTTP_IO)); ZeroMem
> (&HttpConfigData,
> >>>>>>> + sizeof (EFI_HTTP_CONFIG_DATA));
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Create the HTTP child instance and get the HTTP protocol.
> >>>>>>> + //
> >>>>>>> + Status = NetLibCreateServiceChild (
> >>>>>>> + Controller,
> >>>>>>> + Image,
> >>>>>>> + &gEfiHttpServiceBindingProtocolGuid,
> >>>>>>> + &HttpIo->Handle
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Status = gBS->OpenProtocol (
> >>>>>>> + HttpIo->Handle,
> >>>>>>> + &gEfiHttpProtocolGuid,
> >>>>>>> + (VOID **) &Http,
> >>>>>>> + Image,
> >>>>>>> + Controller,
> >>>>>>> + EFI_OPEN_PROTOCOL_BY_DRIVER
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status) || (Http == NULL)) {
> >>>>>>> + goto ON_ERROR;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Init the configuration data and configure the HTTP child.
> >>>>>>> + //
> >>>>>>> + HttpIo->Image = Image;
> >>>>>>> + HttpIo->Controller = Controller;
> >>>>>>> + HttpIo->IpVersion = IpVersion;
> >>>>>>> + HttpIo->Http = Http;
> >>>>>>> + HttpIo->Callback = Callback;
> >>>>>>> + HttpIo->Context = Context;
> >>>>>>> +
> >>>>>>> + if (ConfigData != NULL) {
> >>>>>>> + if (HttpIo->IpVersion == IP_VERSION_4) {
> >>>>>>> + HttpConfigData.LocalAddressIsIPv6 = FALSE;
> >>>>>>> + HttpConfigData.HttpVersion = ConfigData-
> >>> Config4.HttpVersion;
> >>>>>>> + HttpConfigData.TimeOutMillisec = ConfigData-
> >>>>>>> Config4.RequestTimeOut;
> >>>>>>> +
> >>>>>>> + Http4AccessPoint.UseDefaultAddress = ConfigData-
> >>>>>>> Config4.UseDefaultAddress;
> >>>>>>> + Http4AccessPoint.LocalPort = ConfigData-
> >Config4.LocalPort;
> >>>>>>> + IP4_COPY_ADDRESS (&Http4AccessPoint.LocalAddress,
> >>>> &ConfigData-
> >>>>>>> Config4.LocalIp);
> >>>>>>> + IP4_COPY_ADDRESS (&Http4AccessPoint.LocalSubnet,
> >> &ConfigData-
> >>>>>>> Config4.SubnetMask);
> >>>>>>> + HttpConfigData.AccessPoint.IPv4Node = &Http4AccessPoint;
> >>>>>>> + } else {
> >>>>>>> + HttpConfigData.LocalAddressIsIPv6 = TRUE;
> >>>>>>> + HttpConfigData.HttpVersion = ConfigData-
> >>> Config6.HttpVersion;
> >>>>>>> + HttpConfigData.TimeOutMillisec = ConfigData-
> >>>>>>> Config6.RequestTimeOut;
> >>>>>>> +
> >>>>>>> + Http6AccessPoint.LocalPort = ConfigData-
> >Config6.LocalPort;
> >>>>>>> + IP6_COPY_ADDRESS (&Http6AccessPoint.LocalAddress,
> >>>> &ConfigData-
> >>>>>>> Config6.LocalIp);
> >>>>>>> + HttpConfigData.AccessPoint.IPv6Node = &Http6AccessPoint;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Status = Http->Configure (Http, &HttpConfigData);
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + goto ON_ERROR;
> >>>>>>> + }
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Create events for variuos asynchronous operations.
> >>>>>>> + //
> >>>>>>> + Status = gBS->CreateEvent (
> >>>>>>> + EVT_NOTIFY_SIGNAL,
> >>>>>>> + TPL_NOTIFY,
> >>>>>>> + HttpIoNotify,
> >>>>>>> + &HttpIo->IsTxDone,
> >>>>>>> + &Event
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + goto ON_ERROR;
> >>>>>>> + }
> >>>>>>> + HttpIo->ReqToken.Event = Event;
> >>>>>>> + HttpIo->ReqToken.Message = &HttpIo->ReqMessage;
> >>>>>>> +
> >>>>>>> + Status = gBS->CreateEvent (
> >>>>>>> + EVT_NOTIFY_SIGNAL,
> >>>>>>> + TPL_NOTIFY,
> >>>>>>> + HttpIoNotify,
> >>>>>>> + &HttpIo->IsRxDone,
> >>>>>>> + &Event
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + goto ON_ERROR;
> >>>>>>> + }
> >>>>>>> + HttpIo->RspToken.Event = Event;
> >>>>>>> + HttpIo->RspToken.Message = &HttpIo->RspMessage;
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Create TimeoutEvent for response // Status = gBS-
> >CreateEvent
> >>>>>>> + (
> >>>>>>> + EVT_TIMER,
> >>>>>>> + TPL_CALLBACK,
> >>>>>>> + NULL,
> >>>>>>> + NULL,
> >>>>>>> + &Event
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + goto ON_ERROR;
> >>>>>>> + }
> >>>>>>> + HttpIo->TimeoutEvent = Event;
> >>>>>>> + return EFI_SUCCESS;
> >>>>>>> +
> >>>>>>> +ON_ERROR:
> >>>>>>> + HttpIoDestroyIo (HttpIo);
> >>>>>>> +
> >>>>>>> + return Status;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Synchronously send a HTTP REQUEST message to the server.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] Request A pointer to storage such data as URL
> >> and
> >>>>>> HTTP method.
> >>>>>>> + @param[in] HeaderCount Number of HTTP header structures
> in
> >>>>>> Headers list.
> >>>>>>> + @param[in] Headers Array containing list of HTTP headers.
> >>>>>>> + @param[in] BodyLength Length in bytes of the HTTP body.
> >>>>>>> + @param[in] Body Body associated with the HTTP request.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP request is trasmitted.
> >>>>>>> + @retval EFI_INVALID_PARAMETER One or more parameters are
> >>>> invalid.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval EFI_DEVICE_ERROR An unexpected network or
> system
> >>>> error
> >>>>>> occurred.
> >>>>>>> + @retval Others Other errors as indicated.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoSendRequest (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN EFI_HTTP_REQUEST_DATA *Request,
> >>>>>>> + IN UINTN HeaderCount,
> >>>>>>> + IN EFI_HTTP_HEADER *Headers,
> >>>>>>> + IN UINTN BodyLength,
> >>>>>>> + IN VOID *Body
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + EFI_STATUS Status;
> >>>>>>> + EFI_HTTP_PROTOCOL *Http;
> >>>>>>> +
> >>>>>>> + if (HttpIo == NULL || HttpIo->Http == NULL) {
> >>>>>>> + return EFI_INVALID_PARAMETER;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + HttpIo->ReqToken.Status = EFI_NOT_READY;
> >>>>>>> + HttpIo->ReqToken.Message->Data.Request = Request;
> >>>>>>> + HttpIo->ReqToken.Message->HeaderCount = HeaderCount;
> >>>>>>> + HttpIo->ReqToken.Message->Headers = Headers;
> >>>>>>> + HttpIo->ReqToken.Message->BodyLength = BodyLength;
> >>>>>>> + HttpIo->ReqToken.Message->Body = Body;
> >>>>>>> +
> >>>>>>> + if (HttpIo->Callback != NULL) {
> >>>>>>> + Status = HttpIo->Callback (
> >>>>>>> + HttpIoRequest,
> >>>>>>> + HttpIo->ReqToken.Message,
> >>>>>>> + HttpIo->Context
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Queue the request token to HTTP instances.
> >>>>>>> + //
> >>>>>>> + Http = HttpIo->Http;
> >>>>>>> + HttpIo->IsTxDone = FALSE;
> >>>>>>> + Status = Http->Request (
> >>>>>>> + Http,
> >>>>>>> + &HttpIo->ReqToken
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Poll the network until transmit finish.
> >>>>>>> + //
> >>>>>>> + while (!HttpIo->IsTxDone) {
> >>>>>>> + Http->Poll (Http);
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + return HttpIo->ReqToken.Status;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Synchronously receive a HTTP RESPONSE message from the
> server.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] RecvMsgHeader TRUE to receive a new HTTP
> >> response
> >>>>>> (from message header).
> >>>>>>> + FALSE to continue receive the previous response
> >>>> message.
> >>>>>>> + @param[out] ResponseData Point to a wrapper of the
> received
> >>>>>> response data.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP response is received.
> >>>>>>> + @retval EFI_INVALID_PARAMETER One or more parameters are
> >>>> invalid.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval EFI_DEVICE_ERROR An unexpected network or
> system
> >>>> error
> >>>>>> occurred.
> >>>>>>> + @retval Others Other errors as indicated.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoRecvResponse (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN BOOLEAN RecvMsgHeader,
> >>>>>>> + OUT HTTP_IO_RESPONSE_DATA *ResponseData
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + EFI_STATUS Status;
> >>>>>>> + EFI_HTTP_PROTOCOL *Http;
> >>>>>>> +
> >>>>>>> + if (HttpIo == NULL || HttpIo->Http == NULL || ResponseData ==
> >> NULL)
> >>>> {
> >>>>>>> + return EFI_INVALID_PARAMETER;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Create new TimeoutEvent for response // if
> >>>>>>> + (HttpIo->TimeoutEvent != NULL) {
> >>>>>>> + gBS->CloseEvent (HttpIo->TimeoutEvent);
> >>>>>>> + HttpIo->TimeoutEvent = NULL;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Status = gBS->CreateEvent (
> >>>>>>> + EVT_TIMER,
> >>>>>>> + TPL_CALLBACK,
> >>>>>>> + NULL,
> >>>>>>> + NULL,
> >>>>>>> + &HttpIo->TimeoutEvent
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>> Is it necessary to recreate the event? Wouldn't this be enough to
> reset
> >> it?
> >>>>> No, we don’t have to recreate this event.
> >>>>>> gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);
> >>>>> I made some changes in this function.
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Start the timer, and wait Timeout seconds to receive the
> header
> >>>>>> packet.
> >>>>>>> + //
> >>>>>>> + Status = gBS->SetTimer (HttpIo->TimeoutEvent, TimerRelative,
> >>>>>>> + HttpIo->Timeout * TICKS_PER_MS); if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Queue the response token to HTTP instances.
> >>>>>>> + //
> >>>>>>> + HttpIo->RspToken.Status = EFI_NOT_READY; if
> (RecvMsgHeader) {
> >>>>>>> + HttpIo->RspToken.Message->Data.Response =
> >>>>>>> + &ResponseData->Response; } else {
> >>>>>>> + HttpIo->RspToken.Message->Data.Response = NULL; }
> >>>>>>> + HttpIo->RspToken.Message->HeaderCount = 0;
> >>>>>>> + HttpIo->RspToken.Message->Headers = NULL;
> >>>>>>> + HttpIo->RspToken.Message->BodyLength = ResponseData-
> >>>>>>> BodyLength;
> >>>>>>> + HttpIo->RspToken.Message->Body = ResponseData->Body;
> >>>>>>> +
> >>>>>>> + Http = HttpIo->Http;
> >>>>>>> + HttpIo->IsRxDone = FALSE;
> >>>>>>> + Status = Http->Response (
> >>>>>>> + Http,
> >>>>>>> + &HttpIo->RspToken
> >>>>>>> + );
> >>>>>>> +
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Poll the network until receive finish.
> >>>>>>> + //
> >>>>>>> + while (!HttpIo->IsRxDone && ((HttpIo->TimeoutEvent == NULL)
> ||
> >>>>>> EFI_ERROR (gBS->CheckEvent (HttpIo->TimeoutEvent)))) {
> >>>>>>> + Http->Poll (Http);
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + gBS->SetTimer (HttpIo->TimeoutEvent, TimerCancel, 0);
> >>>>>>> +
> >>>>>>> + if (!HttpIo->IsRxDone) {
> >>>>>>> + //
> >>>>>>> + // Timeout occurs, cancel the response token.
> >>>>>>> + //
> >>>>>>> + Http->Cancel (Http, &HttpIo->RspToken);
> >>>>>>> +
> >>>>>>> + Status = EFI_TIMEOUT;
> >>>>>>> +
> >>>>>>> + return Status;
> >>>>>>> + } else {
> >>>>>>> + HttpIo->IsRxDone = FALSE;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + if ((HttpIo->Callback != NULL) &&
> >>>>>>> + (HttpIo->RspToken.Status == EFI_SUCCESS || HttpIo-
> >>>>>>> RspToken.Status == EFI_HTTP_ERROR)) {
> >>>>>>> + Status = HttpIo->Callback (
> >>>>>>> + HttpIoResponse,
> >>>>>>> + HttpIo->RspToken.Message,
> >>>>>>> + HttpIo->Context
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Store the received data into the wrapper.
> >>>>>>> + //
> >>>>>>> + ResponseData->Status = HttpIo->RspToken.Status;
> >>>>>>> + ResponseData->HeaderCount = HttpIo->RspToken.Message-
> >>>>>>> HeaderCount;
> >>>>>>> + ResponseData->Headers = HttpIo->RspToken.Message-
> >Headers;
> >>>>>>> + ResponseData->BodyLength = HttpIo->RspToken.Message-
> >>>>>>> BodyLength;
> >>>>>>> +
> >>>>>>> + return Status;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Get the value of the content length if there is a "Content-
> Length"
> >>>> header.
> >>>>>>> +
> >>>>>>> + @param[in] HeaderCount Number of HTTP header
> structures
> >> in
> >>>>>> Headers.
> >>>>>>> + @param[in] Headers Array containing list of HTTP headers.
> >>>>>>> + @param[out] ContentLength Pointer to save the value of the
> >>>> content
> >>>>>> length.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS Successfully get the content length.
> >>>>>>> + @retval EFI_NOT_FOUND No "Content-Length" header in
> the
> >>>>>> Headers.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoGetContentLength (
> >>>>>>> + IN UINTN HeaderCount,
> >>>>>>> + IN EFI_HTTP_HEADER *Headers,
> >>>>>>> + OUT UINTN *ContentLength
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + EFI_HTTP_HEADER *Header;
> >>>>>>> +
> >>>>>>> + Header = HttpFindHeader (HeaderCount, Headers,
> >>>>>>> + HTTP_HEADER_CONTENT_LENGTH); if (Header == NULL) {
> >>>>>>> + return EFI_NOT_FOUND;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + return AsciiStrDecimalToUintnS (Header->FieldValue, (CHAR8 **)
> >>>>>>> +NULL, ContentLength); }
> >>>>>>> +/**
> >>>>>>> + Send HTTP request in chunks.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] SendChunkProcess Pointer to current chunk
> process
> >>>>>> status.
> >>>>>>> + @param[in] RequestMessage Request to send.
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS Successfully to send chunk data
> >> according
> >>>> to
> >>>>>> SendChunkProcess.
> >>>>>>> + @retval Other Other errors.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoSendChunkedTransfer (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN HTTP_IO_SEND_CHUNK_PROCESS *SendChunkProcess,
> >>>>>>> + IN EFI_HTTP_MESSAGE *RequestMessage
> >>>>>>> +)
> >>>>>>> +{
> >>>>>>> + EFI_STATUS Status;
> >>>>>>> + EFI_HTTP_HEADER *NewHeaders;
> >>>>>>> + EFI_HTTP_HEADER *ContentLengthHeader;
> >>>>>>> + UINTN AddNewHeader;
> >>>>>>> + UINTN HeaderCount;
> >>>>>>> + CHAR8 *MessageBody;
> >>>>>>> + UINTN MessageBodyLength;
> >>>>>>> + CHAR8 ChunkLengthStr [HTTP_IO_CHUNK_SIZE_STRING_LEN];
> >>>>>>> + EFI_HTTP_REQUEST_DATA *SentRequestData;
> >>>>>> This is a new function and I already see a difference in the coding
> >> standard.
> >>>>>> Please align variable names like in previous functions.
> >>>>> Done
> >>>>>
> >>>>>>> +
> >>>>>>> + AddNewHeader = 0;
> >>>>>>> + NewHeaders = NULL;
> >>>>>>> + MessageBody = NULL;
> >>>>>>> + ContentLengthHeader = NULL;
> >>>>>>> + MessageBodyLength = 0;
> >>>>>> Alignment of assignments.
> >>>>> Done
> >>>>>
> >>>>>>> +
> >>>>>>> + switch (*SendChunkProcess) {
> >>>>>>> + case HttpIoSendChunkHeaderZeroContent:
> >>>>>> Case spacing: 2 spaces. Applies throughout new code.
> >>>>>>> + ContentLengthHeader =
> >>>>>>> + HttpFindHeader(RequestMessage->HeaderCount,
> >> RequestMessage-
> >>>>>>> Headers,
> >>>>>>> + HTTP_HEADER_CONTENT_LENGTH);
> >>>>>> Spacing after function call name. This applies from this point until the
> >> end
> >>>> of
> >>>>>> patch.
> >>>>> Done
> >>>>>>> + if (ContentLengthHeader == NULL) {
> >>>>>>> + AddNewHeader = 1;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + NewHeaders = AllocateZeroPool((RequestMessage-
> >>> HeaderCount
> >>>> +
> >>>>>>> + AddNewHeader) * sizeof(EFI_HTTP_HEADER));
> >>>>>> Lack of NULL pointer test for NewHeaders (out of memory case).
> >>>>>>> + CopyMem ((VOID*)NewHeaders, (VOID *)RequestMessage-
> >>>>> Headers,
> >>>>>> RequestMessage->HeaderCount * sizeof (EFI_HTTP_HEADER));
> >>>>>>> + if (AddNewHeader == 0) {
> >>>>>>> + //
> >>>>>>> + // Override content-length to Transfer-Encoding.
> >>>>>>> + //
> >>>>>>> + ContentLengthHeader = HttpFindHeader (RequestMessage-
> >>>>>>> HeaderCount, NewHeaders, HTTP_HEADER_CONTENT_LENGTH);
> >>>>>>> + ContentLengthHeader->FieldName = NULL;
> >>>>>>> + ContentLengthHeader->FieldValue = NULL;
> >>>>>>> + } else {
> >>>>>>> + ContentLengthHeader = NewHeaders + RequestMessage-
> >>>>>>> HeaderCount;
> >>>>>>> + }
> >>>>>>> + HttpSetFieldNameAndValue(ContentLengthHeader,
> >>>>>> HTTP_HEADER_TRANSFER_ENCODING,
> >>>>>> HTTP_HEADER_TRANSFER_ENCODING_CHUNKED);
> >>>>>>> + HeaderCount = RequestMessage->HeaderCount +
> >> AddNewHeader;
> >>>>>> Move HeaderCount assignment before NewHeaders allocation. Use
> >>>>>> HeaderCount as argument for NewHeaders allocation.
> >>>>>>> + MessageBodyLength = 0;
> >>>>>>> + MessageBody = NULL;
> >>>>>>> + SentRequestData = RequestMessage->Data.Request;
> >>>>>>> + break;
> >>>>>>> +
> >>>>>>> + case HttpIoSendChunkContent:
> >>>>>>> + HeaderCount = 0;
> >>>>>>> + NewHeaders = NULL;
> >>>>>>> + SentRequestData = NULL;
> >>>>>>> + if (RequestMessage->BodyLength >
> >>>> HTTP_IO_MAX_SEND_PAYLOAD) {
> >>>>>>> + MessageBodyLength = HTTP_IO_MAX_SEND_PAYLOAD;
> >>>>>>> + } else {
> >>>>>>> + MessageBodyLength = RequestMessage->BodyLength;
> >>>>>>> + }
> >>>>>>> + AsciiSPrint (ChunkLengthStr,
> HTTP_IO_CHUNK_SIZE_STRING_LEN,
> >>>>>>> + "%x%c%c", MessageBodyLength,
> >> CHUNKED_TRNASFER_CODING_CR,
> >>>>>>> + CHUNKED_TRNASFER_CODING_LF);
> >>>>>> Line too long, break down in accordance to coding standard.
> >>>>> Done
> >>>>>
> >>>>>>> + MessageBody = AllocatePool (AsciiStrLen (ChunkLengthStr) +
> >>>>>> MessageBodyLength + 2);
> >>>>>>> + if (MessageBody == NULL) {
> >>>>>>> + DEBUG((DEBUG_ERROR, "Not enough memory for chunk
> >>>>>> transfer\n"));
> >>>>>>> + return EFI_OUT_OF_RESOURCES;
> >>>>>>> + }
> >>>>>>> + CopyMem (MessageBody, ChunkLengthStr, AsciiStrLen
> >>>>>> (ChunkLengthStr));
> >>>>>>> + CopyMem (MessageBody + AsciiStrLen (ChunkLengthStr),
> >>>>>> RequestMessage->Body, MessageBodyLength);
> >>>>>>> + *(MessageBody + AsciiStrLen (ChunkLengthStr) +
> >>>> MessageBodyLength)
> >>>>>> = CHUNKED_TRNASFER_CODING_CR;
> >>>>>>> + *(MessageBody + AsciiStrLen (ChunkLengthStr) +
> >>>> MessageBodyLength
> >>>>>> + 1) = CHUNKED_TRNASFER_CODING_LF;
> >>>>>>> + RequestMessage->BodyLength -= MessageBodyLength;
> >>>>>>> + RequestMessage->Body = (VOID *)((CHAR8
> *)RequestMessage-
> >>>>>>> Body + MessageBodyLength);
> >>>>>>> + MessageBodyLength += (AsciiStrLen (ChunkLengthStr) + 2);
> >>>>>> This block could use some spacing and comments to improve
> >> readability.
> >>>>> Done
> >>>>>
> >>>>>>> + if (RequestMessage->BodyLength == 0) {
> >>>>>>> + *SendChunkProcess = HttpIoSendChunkEndChunk;
> >>>>>>> + }
> >>>>>>> + break;
> >>>>>>> +
> >>>>>>> + case HttpIoSendChunkEndChunk:
> >>>>>>> + HeaderCount = 0;
> >>>>>>> + NewHeaders = NULL;
> >>>>>>> + SentRequestData = NULL;
> >>>>>>> + AsciiSPrint (ChunkLengthStr,
> HTTP_IO_CHUNK_SIZE_STRING_LEN,
> >>>>>> "0%c%c%c%c",
> >>>>>>> + CHUNKED_TRNASFER_CODING_CR,
> >>>>>> CHUNKED_TRNASFER_CODING_LF,
> >>>>>>> + CHUNKED_TRNASFER_CODING_CR,
> >>>>>> CHUNKED_TRNASFER_CODING_LF
> >>>>>>> + );
> >>>>>> Please break function calls in accordance with coding standard.
> >>>>> Done
> >>>>>>> + MessageBody = AllocatePool (AsciiStrLen(ChunkLengthStr));
> >>>>>>> + if (MessageBody == NULL) {
> >>>>>>> + DEBUG((DEBUG_ERROR, "Not enough memory for the end
> >> chunk
> >>>>>> transfer\n"));
> >>>>>>> + return EFI_OUT_OF_RESOURCES;
> >>>>>>> + }
> >>>>>>> + CopyMem (MessageBody, ChunkLengthStr, AsciiStrLen
> >>>>>> (ChunkLengthStr));
> >>>>>>> + MessageBodyLength = AsciiStrLen(ChunkLengthStr);
> >>>>>>> + *SendChunkProcess = HttpIoSendChunkFinish;
> >>>>>>> + break;
> >>>>>>> +
> >>>>>>> + default:
> >>>>>>> + return EFI_INVALID_PARAMETER;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + Status = HttpIoSendRequest(
> >>>>>>> + HttpIo,
> >>>>>>> + SentRequestData,
> >>>>>>> + HeaderCount,
> >>>>>>> + NewHeaders,
> >>>>>>> + MessageBodyLength,
> >>>>>>> + MessageBody
> >>>>>>> + );
> >>>>>>> + if (ContentLengthHeader != NULL) {
> >>>>>>> + if (ContentLengthHeader->FieldName != NULL) {
> >>>>>>> + FreePool(ContentLengthHeader->FieldName);
> >>>>>>> + }
> >>>>>>> + if (ContentLengthHeader->FieldValue != NULL) {
> >>>>>>> + FreePool(ContentLengthHeader->FieldValue);
> >>>>>>> + }
> >>>>>>> + ContentLengthHeader = NULL;
> >>>>>> NULL assignments are not necessary here as we are exiting the
> >> function
> >>>> and
> >>>>>> those variables will not be used.
> >>>>> Right, fixed.
> >>>>>>> + }
> >>>>>>> + if (NewHeaders != NULL) {
> >>>>>>> + FreePool(NewHeaders);
> >>>>>>> + NewHeaders = NULL;
> >>>>>>> + }
> >>>>>>> + if (MessageBody != NULL) {
> >>>>>>> + FreePool(MessageBody);
> >>>>>>> + MessageBody = NULL;
> >>>>>>> + }
> >>>>>>> + return Status;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>> +/**
> >>>>>>> + Synchronously receive a HTTP RESPONSE message from the
> server.
> >>>>>>> +
> >>>>>>> + @param[in] HttpIo The HttpIo wrapping the HTTP service.
> >>>>>>> + @param[in] HeaderCount Number of headers in Headers.
> >>>>>>> + @param[in] Headers Array containing list of HTTP headers.
> >>>>>>> + @param[out] ChunkListHead A pointer to receivce list head of
> >>>> chunked
> >>>>>> data.
> >>>>>> Spelling: receive.
> >>>>> Fixed.
> >>>>>
> >>>>>>> + Caller has to release memory of ChunkListHead
> >>>>>>> + and all list entries.
> >>>>>>> + @param[out] ContentLength Total content length
> >>>>>>> +
> >>>>>>> + @retval EFI_SUCCESS The HTTP chunked transfer is
> received.
> >>>>>>> + @retval EFI_NOT_FOUND No chunked transfer coding
> header
> >>>> found.
> >>>>>>> + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
> >>>>>>> + @retval EFI_INVALID_PARAMETER Improper parameters.
> >>>>>>> + @retval Others Other errors as indicated.
> >>>>>>> +
> >>>>>>> +**/
> >>>>>>> +EFI_STATUS
> >>>>>>> +HttpIoGetChunkedTransferContent (
> >>>>>>> + IN HTTP_IO *HttpIo,
> >>>>>>> + IN UINTN HeaderCount,
> >>>>>>> + IN EFI_HTTP_HEADER *Headers,
> >>>>>>> + OUT LIST_ENTRY **ChunkListHead,
> >>>>>>> + OUT UINTN *ContentLength
> >>>>>>> + )
> >>>>>>> +{
> >>>>>>> + EFI_HTTP_HEADER *Header;
> >>>>>>> + CHAR8 ChunkSizeAscii[256];
> >>>>>>> + EFI_STATUS Status;
> >>>>>>> + UINTN Index;
> >>>>>>> + HTTP_IO_RESPONSE_DATA ResponseData;
> >>>>>>> + UINTN TotalLength;
> >>>>>>> + LIST_ENTRY *HttpChunks;
> >>>>>>> + HTTP_IO_CHUNKS *ThisChunk;
> >>>>>> Variable alignment.
> >>>>>>> + LIST_ENTRY *ThisListEntry;
> >>>>>>> +
> >>>>>>> + if (ChunkListHead == NULL || ContentLength == NULL) {
> >>>>>>> + return EFI_INVALID_PARAMETER;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + *ContentLength = 0;
> >>>>>>> + Header = HttpFindHeader (HeaderCount, Headers,
> >>>>>>> + HTTP_HEADER_TRANSFER_ENCODING); if (Header == NULL) {
> >>>>>>> + return EFI_NOT_FOUND;
> >>>>>>> + }
> >>>>>>> + if (AsciiStrCmp (Header->FieldValue,
> >>>>>>> + HTTP_HEADER_TRANSFER_ENCODING_CHUNKED) == 0) {
> >>>>>> Please do a negation comparison instead and return. It reduces one
> >> level
> >>>> of
> >>>>>> indentation.
> >>>>> Done
> >>>>>>> + //
> >>>>>>> + // Loop to get all chunks.
> >>>>>>> + //
> >>>>>> Please avoid empty single-line comments when starting and ending
> >>>>>> comment block.
> >>>>>>> + TotalLength = 0;
> >>>>>>> + HttpChunks = (LIST_ENTRY *)AllocateZeroPool (sizeof
> >> (LIST_ENTRY));
> >>>>>>> + if (HttpChunks == NULL) {
> >>>>>>> + Status = EFI_OUT_OF_RESOURCES;
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> + InitializeListHead (HttpChunks);
> >>>>>> Add a bit of spacing above to improve readability.
> >>>>> Fixed
> >>>>>>> + DEBUG ((DEBUG_INFO, " Chunked transfer\n"));
> >>>>>>> + while (TRUE) {
> >>>>>>> + ZeroMem((VOID *)&ResponseData,
> >>>>>> sizeof(HTTP_IO_RESPONSE_DATA));
> >>>>>>> + ResponseData.BodyLength =
> >>>>>> HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH;
> >>>>>>> + ResponseData.Body = ChunkSizeAscii;
> >>>>>>> + Status = HttpIoRecvResponse (
> >>>>>>> + HttpIo,
> >>>>>>> + FALSE,
> >>>>>>> + &ResponseData
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + return Status;
> >>>>>>> + }
> >>>>>> Returning here creates memory leak risk - chunks previously
> received
> >> will
> >>>> not
> >>>>>> be freed.
> >>>>> Fixed
> >>>>>>> + //
> >>>>>>> + // Decoding Chunked Transfer Coding.
> >>>>>>> + // Only decode chunk-size and last chunk.
> >>>>>>> + //
> >>>>>>> + DEBUG ((DEBUG_INFO, " Chunk HTTP Response StatusCode -
> >>>> %d\n",
> >>>>>> ResponseData.Response.StatusCode));
> >>>>>>> + //
> >>>>>>> + // Break if this is last chunk.
> >>>>>>> + //
> >>>>>>> + if (ChunkSizeAscii [0] ==
> >>>> CHUNKED_TRNASFER_CODING_LAST_CHUNK)
> >>>>>> {
> >>>>>>> + Status = EFI_SUCCESS;
> >>>>>>> + DEBUG ((DEBUG_INFO, " Last chunk\n"));
> >>>>>>> + ThisChunk = (HTTP_IO_CHUNKS *)AllocateZeroPool (sizeof
> >>>>>> (HTTP_IO_CHUNKS));
> >>>>>>> + if (ThisChunk == NULL) {
> >>>>>>> + Status = EFI_OUT_OF_RESOURCES;
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> + InitializeListHead (&ThisChunk->NextChunk);
> >>>>>>> + ThisChunk->Length = ResponseData.BodyLength - 1 - 2; //
> Minus
> >>>>>> sizeof '0' and CRLF.
> >>>>>>> + ThisChunk->Data = (CHAR8 *)AllocatePool (ThisChunk-
> >Length);
> >>>>>>> + if (ThisChunk->Data == NULL) {
> >>>>>>> + FreePool ((UINT8 *)ThisChunk);
> >>>>>>> + Status = EFI_OUT_OF_RESOURCES;
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> + CopyMem ((UINT8 *)ThisChunk->Data, (UINT8
> >>>> *)ResponseData.Body
> >>>>>> + 1, ThisChunk->Length);
> >>>>>>> + TotalLength += ThisChunk->Length;
> >>>>>>> + InsertTailList (HttpChunks, &ThisChunk->NextChunk);
> >>>>>>> + break;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + //
> >>>>>>> + // Get the chunk length
> >>>>>>> + //
> >>>>>>> + Index = 0;
> >>>>>>> + while ((ChunkSizeAscii [Index] !=
> >>>>>> CHUNKED_TRNASFER_CODING_EXTENSION_SAPERATOR) &&
> >>>>>>> + (ChunkSizeAscii [Index] !=
> >>>>>>> + (CHAR8)CHUNKED_TRNASFER_CODING_CR) &&
> >>>>>> Spelling errors in macros above.
> >>>>> Oops. BZ is submitted for this typo in http11.h.
> >>>>> INVALID URI REMOVED
> >>>> 3A__bugzilla.tianocore.org_show-5Fbug.cgi-3Fid-
> >>>>
> >>
> 3D3019&d=DwIDaQ&c=C5b8zRQO1miGmBeVZ2LFWg&r=_SN6FZBN4Vgi4Ulks
> >>
> kz6qU3NYRO03nHp9P7Z5q59A3E&m=f6zs_mrzwCCYwQSl3p4Nbuib7Ln4gVcO
> >>>> KS74o-
> Xc524&s=g1WHLCl8Uzm8YKLYknM2Y7T0d4gT7fv_58qhc4Qejj0&e=
> >>>>> Patch is set to the mailing list for review.
> >>>>>
> >>>>>
> >>>>>>> + (Index !=
> >>>>>> HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH)) {
> >>>>>>> + Index ++;
> >>>>>>> + };
> >>>>>>> + if (Index ==
> >>>> HTTP_IO_CHUNKED_TRANSFER_CODING_DATA_LENGTH)
> >>>>>> {
> >>>>>>> + return EFI_NOT_FOUND;
> >>>>>>> + }
> >>>>>> Again - memory leak.
> >>>>> Fixed
> >>>>>
> >>>>>>> + ChunkSizeAscii[Index] = 0;
> >>>>>>> + AsciiStrHexToUintnS (ChunkSizeAscii, NULL, ContentLength);
> >>>>>>> + DEBUG ((DEBUG_INFO, " Length of this chunk %d\n",
> >>>>>> *ContentLength));
> >>>>>>> + //
> >>>>>>> + // Receive the data;
> >>>>>>> + //
> >>>>>>> + ThisChunk = (HTTP_IO_CHUNKS *)AllocateZeroPool (sizeof
> >>>>>> (HTTP_IO_CHUNKS));
> >>>>>>> + if (ThisChunk == NULL) {
> >>>>>>> + Status = EFI_OUT_OF_RESOURCES;
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> + ResponseData.BodyLength = *ContentLength;
> >>>>>>> + ResponseData.Body = (CHAR8 *)AllocatePool
> (*ContentLength);
> >>>>>>> + if (ResponseData.Body == NULL) {
> >>>>>>> + FreePool (ThisChunk);
> >>>>>>> + Status = EFI_OUT_OF_RESOURCES;
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> + InitializeListHead (&ThisChunk->NextChunk);
> >>>>>>> + ThisChunk->Length = *ContentLength;
> >>>>>>> + ThisChunk->Data = ResponseData.Body;
> >>>>>>> + InsertTailList (HttpChunks, &ThisChunk->NextChunk);
> >>>>>>> + Status = HttpIoRecvResponse (
> >>>>>>> + HttpIo,
> >>>>>>> + FALSE,
> >>>>>>> + &ResponseData
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> + //
> >>>>>>> + // Read CRLF
> >>>>>>> + //
> >>>>>>> + ZeroMem((VOID *)&ResponseData,
> >>>>>> sizeof(HTTP_IO_RESPONSE_DATA));
> >>>>>>> + ResponseData.BodyLength = 2;
> >>>>>>> + ResponseData.Body = ChunkSizeAscii;
> >>>>>>> + Status = HttpIoRecvResponse (
> >>>>>>> + HttpIo,
> >>>>>>> + FALSE,
> >>>>>>> + &ResponseData
> >>>>>>> + );
> >>>>>>> + if (EFI_ERROR (Status)) {
> >>>>>>> + goto DeleterChunks;
> >>>>>>> + }
> >>>>>>> +
> >>>>>>> + TotalLength += *ContentLength;
> >>>>>> The following code requires some kind of protection against
> receiving
> >> an
> >>>>>> infinite number of chunks.
> >>>>>> Currently I could just not send a last chunk and wait for the platform
> to
> >>>> crash
> >>>>>> or/and run out of memory :)
> >>>>>>
> >>>>> Good point! However, I can't think of any good way to prevent from
> this
> >>>> happens. This depends on the reliability of content provider and how
> the
> >>>> web service handles chunk transfer, right?
> >>>>> From system firmware viewpoint, we would connect to a trusted
> >> content
> >>>> source for either HTTP boot image and Redfish service resource.
> >>>>> Do you think this concern is valid for the real practice?
> >>>>>
> >>>>> Or give it a limited size of payload? Like the size larger than 1G could
> be
> >>>> considered as an ill content?
> >>>> What would be the largest payload that you would like to use
> >>>> chunk-transfer for?
> >>> For the HTTP response, whether to use chunk transfer is at the
> discretion
> >> of Redfish service. We currently can only tell if the response payload is in
> >> chunk transfer or not using Transfer-Encoding HTTP response header but
> not
> >> able to predict the size of payload unless we get the first chunk.
> >>> In the real practice, I see a large payload like AttributeRegistry is
> >> transferred back in chunk, however, I also see some small size payload is
> >> transferred back in chunk transfer as well.
> >>>> I see that the chunked transfer is not being currently used in HTTP
> >>>> Boot, so we should stick to current use case - Redfish.
> >>> Yes, currently only RedfishPkg use HTTP chunk transfer APIs defined in
> >> DxeHttpIoLib. But what do you mean to stick the use case to Redfish only?
> >> Those chunk transfer related APIs could be commonly used by any edk2
> >> HTTP clients need chunk transfer although we only have two use cases
> (and
> >> only Redfish uses it so far).
> >> I only meant that it would be reasonable to come up with a
> >> chunk-transfer limit that is dictated solely by Redfish use case, since
> >> it is currently the only one around.
> >> In case other SW pieces would like to consume HTTP I/O library for
> >> chunk-transfer and see that the limit is too small, they could propose a
> >> patch to extend it.
> > Yes, we can do it.
> >> The other approach would be to somehow dynamically assess the limit by
> >> looking at how much free memory is available on the platform.
> >> Can we estimate what would be the largest payload Redfish would like to
> >> push through?
> > The biggest payload of Redfish resource which sent back to client could be
> AttaibuteRegistry. One example here is the raw text JSON file of
> AttaibuteRegistry is 1.2MB, however it is reduced to ~65K using gzip. How big
> the AttaibuteRegistry payload depends on the platform and also depends on
> if Redfish service sends back the payload using gzip.
> > We can just limit it to 10MB for now, that says we break the chunk transfer
> if TotalLength > 10MB. We can adjust it later if any uses case request it. How
> do you think?
> Since the limit is so small, there is no point in checking it against
> total amount of memory. For the time being, we should be fine with the
> limit you have suggested :)
>
> >>>>>>> + };
> >>>>>>> + *ContentLength = TotalLength;
> >>>>>>> + *ChunkListHead = HttpChunks;
> >>>>>>> + DEBUG ((DEBUG_INFO, " Total of lengh of chunks :%d\n",
> >>>>>> TotalLength));
> >>>>>>> + return EFI_SUCCESS;
> >>>>>>> + } else {
> >>>>>>> + return EFI_NOT_FOUND;
> >>>>>>> + }
> >>>>>>> +DeleterChunks:;
> >>>>>> Name this label ExitDeleteChunks and remove the comma.
> >>>>>>> + while (!IsListEmpty (HttpChunks)) {
> >>>>>>> + ThisListEntry = GetFirstNode (HttpChunks);
> >>>>>>> + RemoveEntryList (ThisListEntry);
> >>>>>>> + };
> >>>>>>> + return Status;
> >>>>>>> +}
> >>>>>>> diff --git a/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf
> >>>>>>> b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf
> >>>>>>> new file mode 100644
> >>>>>>> index 0000000000..a02b409547
> >>>>>>> --- /dev/null
> >>>>>>> +++ b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.inf
> >>>>>>> @@ -0,0 +1,43 @@
> >>>>>>> +## @file
> >>>>>>> +# This library instance provides HTTP IO helper functions.
> >>>>>>> +#
> >>>>>>> +# (C) Copyright 2020 Hewlett Packard Enterprise Development
> >> LP<BR>
> >>>> #
> >>>>>>> +SPDX-License-Identifier: BSD-2-Clause-Patent # ##
> >>>>>>> +
> >>>>>>> +[Defines]
> >>>>>>> + INF_VERSION = 0x0001001b
> >>>>>>> + BASE_NAME = DxeHttpIoLib
> >>>>>>> + MODULE_UNI_FILE = DxeHttpIoLib.uni
> >>>>>>> + FILE_GUID = 50B198F8-7986-4F51-A857-CFE4643D59F3
> >>>>>>> + MODULE_TYPE = DXE_DRIVER
> >>>>>>> + VERSION_STRING = 1.0
> >>>>>>> + LIBRARY_CLASS = HttpIoLib| DXE_CORE DXE_DRIVER
> >>>>>> DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION
> >>>>>> UEFI_DRIVER
> >>>>>>> +
> >>>>>>> +#
> >>>>>>> +# The following information is for reference only and not required
> by
> >>>> the
> >>>>>> build tools.
> >>>>>>> +#
> >>>>>>> +# VALID_ARCHITECTURES = IA32 X64 EBC ARM AARM64
> >> RISCV64
> >>>>>>> +#
> >>>>>>> +
> >>>>>>> +[Sources]
> >>>>>>> + DxeHttpIoLib.c
> >>>>>>> +
> >>>>>>> +[Packages]
> >>>>>>> + MdePkg/MdePkg.dec
> >>>>>>> + NetworkPkg/NetworkPkg.dec
> >>>>>>> +
> >>>>>>> +
> >>>>>>> +[LibraryClasses]
> >>>>>>> + BaseLib
> >>>>>>> + BaseMemoryLib
> >>>>>>> + DebugLib
> >>>>>>> + DpcLib
> >>>>>>> + MemoryAllocationLib
> >>>>>>> + PrintLib
> >>>>>>> + UefiBootServicesTableLib
> >>>>>>> +
> >>>>>>> +[Protocols]
> >>>>>>> + gEfiHttpProtocolGuid ## SOMETIMES_CONSUMES
> >>>>>>> +
> >>>>>>> diff --git a/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni
> >>>>>>> b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni
> >>>>>>> new file mode 100644
> >>>>>>> index 0000000000..d419b1a49d
> >>>>>>> --- /dev/null
> >>>>>>> +++ b/NetworkPkg/Library/DxeHttpIoLib/DxeHttpIoLib.uni
> >>>>>>> @@ -0,0 +1,13 @@
> >>>>>>> +// /** @file
> >>>>>>> +// The library instance provides HTTP IO helper functions.
> >>>>>>> +//
> >>>>>>> +// (C) Copyright 2020 Hewlett Packard Enterprise Development
> >> LP<BR>
> >>>>>>> +// SPDX-License-Identifier: BSD-2-Clause-Patent // // **/
> >>>>>>> +
> >>>>>>> +
> >>>>>>> +#string STR_MODULE_ABSTRACT #language en-US "HTTP IO
> >>>> Helper
> >>>>>> Library"
> >>>>>>> +
> >>>>>>> +#string STR_MODULE_DESCRIPTION #language en-US "The
> >> library
> >>>>>> instance provides HTTP IO helper functions."
> >>>>>>> +
> >>>>>
> >>>>>
> >>>>>
> >>>
> >>>
> >>>
> >>>
> >
> >
> >
> >
> >
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#66918): https://edk2.groups.io/g/devel/message/66918
Mute This Topic: https://groups.io/mt/77674866/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-
More information about the edk2-devel-archive
mailing list