/** @file\r
Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
\r
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>\r
\r
This program and the accompanying materials\r
@retval EFI_SUCCESS Operation succeeded.\r
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:\r
This is NULL.\r
- HttpConfigData is NULL.\r
HttpConfigData->LocalAddressIsIPv6 is FALSE and\r
HttpConfigData->IPv4Node is NULL.\r
HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
EFIAPI\r
EfiHttpConfigure (\r
IN EFI_HTTP_PROTOCOL *This,\r
- IN EFI_HTTP_CONFIG_DATA *HttpConfigData\r
+ IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL\r
) \r
{\r
HTTP_PROTOCOL *HttpInstance;\r
// Check input parameters.\r
//\r
if (This == NULL ||\r
- HttpConfigData == NULL ||\r
- ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
- (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL))) {\r
+ (HttpConfigData != NULL && \r
+ ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+ (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
\r
if (HttpConfigData != NULL) {\r
\r
+ if (HttpConfigData->HttpVersion >= HttpVersionUnsupported) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
//\r
// Now configure this HTTP instance.\r
//\r
VOID *UrlParser;\r
EFI_STATUS Status;\r
CHAR8 *HostName;\r
+ UINTN HostNameSize;\r
UINT16 RemotePort;\r
HTTP_PROTOCOL *HttpInstance;\r
BOOLEAN Configure;\r
BOOLEAN ReConfigure;\r
+ BOOLEAN TlsConfigure;\r
CHAR8 *RequestMsg;\r
CHAR8 *Url;\r
UINTN UrlLen;\r
HTTP_TOKEN_WRAP *Wrap;\r
CHAR8 *FileUrl;\r
UINTN RequestMsgSize;\r
+ EFI_HANDLE ImageHandle;\r
\r
//\r
// Initializations\r
//\r
Url = NULL;\r
+ UrlParser = NULL;\r
+ RemotePort = 0;\r
HostName = NULL;\r
RequestMsg = NULL;\r
HostNameStr = NULL;\r
Wrap = NULL;\r
FileUrl = NULL;\r
+ TlsConfigure = FALSE;\r
\r
if ((This == NULL) || (Token == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
Request = HttpMsg->Data.Request;\r
\r
//\r
- // Only support GET, HEAD, PUT and POST method in current implementation.\r
+ // Only support GET, HEAD, PATCH, PUT and POST method in current implementation.\r
//\r
if ((Request != NULL) && (Request->Method != HttpMethodGet) &&\r
- (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost)) {\r
+ (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodPut) && \r
+ (Request->Method != HttpMethodPost) && (Request->Method != HttpMethodPatch)) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
\r
if (Request == NULL) {\r
//\r
- // Request would be NULL only for PUT/POST operation (in the current implementation)\r
+ // Request would be NULL only for PUT/POST/PATCH operation (in the current implementation)\r
//\r
- if ((HttpInstance->Method != HttpMethodPut) && (HttpInstance->Method != HttpMethodPost)) {\r
+ if ((HttpInstance->Method != HttpMethodPut) && \r
+ (HttpInstance->Method != HttpMethodPost) && \r
+ (HttpInstance->Method != HttpMethodPatch)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
//\r
- // For PUT/POST, we need to have the TCP already configured. Bail out if it is not!\r
+ // For PUT/POST/PATCH, we need to have the TCP already configured. Bail out if it is not!\r
//\r
if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
\r
- UnicodeStrToAsciiStr (Request->Url, Url);\r
+ UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);\r
+\r
+ //\r
+ // From the information in Url, the HTTP instance will \r
+ // be able to determine whether to use http or https.\r
+ //\r
+ HttpInstance->UseHttps = IsHttpsUrl (Url);\r
+\r
+ //\r
+ // HTTP is disabled, return directly if the URI is not HTTPS.\r
+ //\r
+ if (!PcdGetBool (PcdAllowHttpConnections) && !(HttpInstance->UseHttps)) {\r
+ \r
+ DEBUG ((EFI_D_ERROR, "EfiHttpRequest: HTTP is disabled.\n"));\r
+\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ //\r
+ // Check whether we need to create Tls child and open the TLS protocol.\r
+ //\r
+ if (HttpInstance->UseHttps && HttpInstance->TlsChildHandle == NULL) {\r
+ //\r
+ // Use TlsSb to create Tls child and open the TLS protocol.\r
+ //\r
+ if (HttpInstance->LocalAddressIsIPv6) {\r
+ ImageHandle = HttpInstance->Service->Ip6DriverBindingHandle;\r
+ } else {\r
+ ImageHandle = HttpInstance->Service->Ip4DriverBindingHandle;\r
+ }\r
+\r
+ HttpInstance->TlsChildHandle = TlsCreateChild (\r
+ ImageHandle,\r
+ &(HttpInstance->TlsSb),\r
+ &(HttpInstance->Tls),\r
+ &(HttpInstance->TlsConfiguration)\r
+ );\r
+ if (HttpInstance->TlsChildHandle == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ TlsConfigure = TRUE;\r
+ }\r
+\r
UrlParser = NULL;\r
Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
if (EFI_ERROR (Status)) {\r
\r
Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
if (EFI_ERROR (Status)) {\r
- RemotePort = HTTP_DEFAULT_PORT;\r
+ if (HttpInstance->UseHttps) {\r
+ RemotePort = HTTPS_DEFAULT_PORT;\r
+ } else {\r
+ RemotePort = HTTP_DEFAULT_PORT;\r
+ }\r
}\r
//\r
// If Configure is TRUE, it indicates the first time to call Request();\r
ReConfigure = FALSE;\r
} else {\r
if ((HttpInstance->RemotePort == RemotePort) &&\r
- (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\r
+ (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) && \r
+ (!HttpInstance->UseHttps || (HttpInstance->UseHttps && \r
+ !TlsConfigure && \r
+ HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring))) {\r
//\r
// Host Name and port number of the request URL are the same with previous call to Request().\r
+ // If Https protocol used, the corresponding SessionState is EfiTlsSessionDataTransferring.\r
// Check whether previous TCP packet sent out.\r
//\r
\r
}\r
\r
if (EFI_ERROR (Status)) {\r
- HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));\r
+ HostNameSize = AsciiStrSize (HostName);\r
+ HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));\r
if (HostNameStr == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Error1;\r
}\r
\r
- AsciiStrToUnicodeStr (HostName, HostNameStr);\r
+ AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);\r
if (!HttpInstance->LocalAddressIsIPv6) {\r
Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
} else {\r
}\r
}\r
\r
-\r
//\r
// Save the RemotePort and RemoteHost.\r
//\r
} else {\r
ASSERT (HttpInstance->Tcp6 != NULL);\r
}\r
+\r
+ if (HttpInstance->UseHttps && !TlsConfigure) {\r
+ Status = TlsCloseSession (HttpInstance);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error1;\r
+ }\r
+ \r
+ TlsCloseTxRxEvent (HttpInstance);\r
+ }\r
+ \r
HttpCloseConnection (HttpInstance);\r
EfiHttpCancel (This, NULL);\r
}\r
if (Request != NULL) {\r
Wrap->TcpWrap.Method = Request->Method;\r
}\r
-\r
- Status = HttpInitTcp (HttpInstance, Wrap, Configure);\r
+ \r
+ Status = HttpInitSession (\r
+ HttpInstance, \r
+ Wrap, \r
+ Configure || ReConfigure, \r
+ TlsConfigure\r
+ );\r
if (EFI_ERROR (Status)) {\r
goto Error2;\r
- } \r
+ }\r
\r
- if (!Configure) {\r
+ if (!Configure && !ReConfigure && !TlsConfigure) {\r
//\r
// For the new HTTP token, create TX TCP token events. \r
//\r
\r
Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize);\r
\r
- if (EFI_ERROR (Status)) {\r
+ if (EFI_ERROR (Status) || NULL == RequestMsg) {\r
goto Error3;\r
}\r
\r
+ ASSERT (RequestMsg != NULL);\r
+\r
//\r
// Every request we insert a TxToken and a response call would remove the TxToken.\r
- // In cases of PUT/POST, after an initial request-response pair, we would do a\r
+ // In cases of PUT/POST/PATCH, after an initial request-response pair, we would do a\r
// continuous request without a response call. So, in such cases, where Request\r
// structure is NULL, we would not insert a TxToken.\r
//\r
return EFI_SUCCESS;\r
\r
Error5:\r
- //\r
- // We would have inserted a TxToken only if Request structure is not NULL.\r
- // Hence check before we do a remove in this error case.\r
- //\r
- if (Request != NULL) {\r
- NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
- }\r
+ //\r
+ // We would have inserted a TxToken only if Request structure is not NULL.\r
+ // Hence check before we do a remove in this error case.\r
+ //\r
+ if (Request != NULL) {\r
+ NetMapRemoveTail (&HttpInstance->TxTokens, NULL);\r
+ }\r
\r
Error4:\r
if (RequestMsg != NULL) {\r
} \r
\r
Error3:\r
- HttpCloseConnection (HttpInstance);\r
+ if (HttpInstance->UseHttps) {\r
+ TlsCloseSession (HttpInstance);\r
+ TlsCloseTxRxEvent (HttpInstance);\r
+ }\r
\r
Error2:\r
+ HttpCloseConnection (HttpInstance);\r
+ \r
HttpCloseTcpConnCloseEvent (HttpInstance);\r
if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {\r
gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
}\r
\r
Error1:\r
-\r
if (HostName != NULL) {\r
FreePool (HostName);\r
}\r
IN VOID *Context\r
)\r
{\r
-\r
EFI_HTTP_TOKEN *Token;\r
HTTP_TOKEN_WRAP *Wrap;\r
HTTP_PROTOCOL *HttpInstance;\r
Wrap = (HTTP_TOKEN_WRAP *) Item->Value;\r
ASSERT (Wrap != NULL);\r
HttpInstance = Wrap->HttpInstance;\r
-\r
- //\r
- // Free resources.\r
- //\r
- NetMapRemoveItem (Map, Item, NULL); \r
\r
if (!HttpInstance->LocalAddressIsIPv6) {\r
- if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) {\r
- gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
- }\r
- \r
if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {\r
- gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event);\r
- }\r
- \r
- if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
- FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
- }\r
+ //\r
+ // Cancle the Token before close its Event.\r
+ //\r
+ HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &Wrap->TcpWrap.Rx4Token.CompletionToken);\r
\r
- } else {\r
- if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) {\r
- gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event);\r
+ //\r
+ // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.\r
+ //\r
+ DispatchDpc ();\r
}\r
-\r
+ } else {\r
if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) {\r
- gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
- }\r
+ //\r
+ // Cancle the Token before close its Event.\r
+ //\r
+ HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &Wrap->TcpWrap.Rx6Token.CompletionToken);\r
\r
- if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
- FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+ //\r
+ // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.\r
+ //\r
+ DispatchDpc ();\r
}\r
}\r
\r
-\r
- FreePool (Wrap);\r
-\r
//\r
// If only one item is to be cancel, return EFI_ABORTED to stop\r
// iterating the map any more.\r
}\r
}\r
\r
- //\r
- // Then check the tokens queued by EfiHttpResponse().\r
- //\r
- Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);\r
- if (EFI_ERROR (Status)) {\r
- if (Token != NULL) {\r
- if (Status == EFI_ABORTED) {\r
- return EFI_SUCCESS;\r
+ if (!HttpInstance->UseHttps) {\r
+ //\r
+ // Then check the tokens queued by EfiHttpResponse(), except for Https.\r
+ //\r
+ Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Token != NULL) {\r
+ if (Status == EFI_ABORTED) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_NOT_FOUND;\r
+ }\r
} else {\r
- return EFI_NOT_FOUND;\r
+ return Status;\r
}\r
+ }\r
+ } else {\r
+ if (!HttpInstance->LocalAddressIsIPv6) {\r
+ HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);\r
} else {\r
- return Status;\r
+ HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);\r
}\r
}\r
-\r
+ \r
return EFI_SUCCESS;\r
}\r
\r
NET_MAP_ITEM *Item;\r
HTTP_TOKEN_WRAP *ValueInItem;\r
UINTN HdrLen;\r
+ NET_FRAGMENT Fragment;\r
\r
if (Wrap == NULL || Wrap->HttpInstance == NULL) {\r
return EFI_INVALID_PARAMETER;\r
SizeofHeaders = 0;\r
BufferSize = 0;\r
EndofHeader = NULL;\r
+ ValueInItem = NULL;\r
+ Fragment.Len = 0;\r
+ Fragment.Bulk = NULL;\r
\r
if (HttpMsg->Data.Response != NULL) {\r
- //\r
- // Need receive the HTTP headers, prepare buffer.\r
- //\r
- Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
-\r
//\r
// Check whether we have cached header from previous call.\r
//\r
//\r
StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1;\r
if (StatusCodeStr == NULL) {\r
+ Status = EFI_NOT_READY;\r
goto Error;\r
}\r
\r
//\r
Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR);\r
if (Tmp == NULL) {\r
+ Status = EFI_NOT_READY;\r
goto Error;\r
}\r
\r
ValueInItem = NULL;\r
\r
//\r
- // In cases of PUT/POST, after an initial request-response pair, we would do a\r
+ // In cases of PUT/POST/PATCH, after an initial request-response pair, we would do a\r
// continuous request without a response call. So, we would not do an insert of\r
// TxToken. After we have sent the complete file, we will call a response to get\r
// a final response from server. In such a case, we would not have any TxTokens.\r
if (SizeofHeaders != 0) {\r
HeaderTmp = AllocateZeroPool (SizeofHeaders);\r
if (HeaderTmp == NULL) {\r
- goto Error;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error2;\r
}\r
\r
CopyMem (HeaderTmp, Tmp, SizeofHeaders);\r
//\r
if (mHttpUtilities == NULL) {\r
Status = EFI_NOT_READY;\r
- goto Error;\r
+ goto Error2;\r
}\r
\r
//\r
&HttpMsg->HeaderCount\r
);\r
if (EFI_ERROR (Status)) {\r
- goto Error;\r
+ goto Error2;\r
}\r
\r
FreePool (HttpHeaders);\r
\r
ASSERT (HttpInstance->MsgParser != NULL);\r
\r
- if (HttpInstance->TimeoutEvent == NULL) {\r
+ //\r
+ // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
+ //\r
+ if (!HttpInstance->UseHttps) {\r
+ Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
+ \r
+ } else {\r
+ if (HttpInstance->TimeoutEvent == NULL) {\r
+ //\r
+ // Create TimeoutEvent for response\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER,\r
+ TPL_CALLBACK,\r
+ NULL,\r
+ NULL,\r
+ &HttpInstance->TimeoutEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
+ }\r
+\r
//\r
- // Create TimeoutEvent for response\r
+ // Start the timer, and wait Timeout seconds to receive the body packet.\r
//\r
- Status = gBS->CreateEvent (\r
- EVT_TIMER,\r
- TPL_CALLBACK,\r
- NULL,\r
- NULL,\r
- &HttpInstance->TimeoutEvent\r
- );\r
+ Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
if (EFI_ERROR (Status)) {\r
- goto Error;\r
+ goto Error2;\r
}\r
- }\r
+ \r
+ Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance->TimeoutEvent);\r
\r
- //\r
- // Start the timer, and wait Timeout seconds to receive the body packet.\r
- //\r
- Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+ \r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
\r
- //\r
- // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
- //\r
- Status = HttpTcpReceiveBody (Wrap, HttpMsg, HttpInstance->TimeoutEvent);\r
+ //\r
+ // Check whether we receive a complete HTTP message.\r
+ //\r
+ Status = HttpParseMessageBody (\r
+ HttpInstance->MsgParser,\r
+ (UINTN) Fragment.Len,\r
+ (CHAR8 *) Fragment.Bulk\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
\r
- gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+ if (HttpIsMessageComplete (HttpInstance->MsgParser)) {\r
+ //\r
+ // Free the MsgParse since we already have a full HTTP message.\r
+ //\r
+ HttpFreeMsgParser (HttpInstance->MsgParser);\r
+ HttpInstance->MsgParser = NULL;\r
+ }\r
\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
+ //\r
+ // We receive part of header of next HTTP msg.\r
+ //\r
+ if (HttpInstance->NextMsg != NULL) {\r
+ HttpMsg->BodyLength = MIN ((UINTN) HttpInstance->NextMsg - (UINTN) Fragment.Bulk, HttpMsg->BodyLength);\r
+ CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);\r
+ \r
+ HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;\r
+ if (HttpInstance->CacheLen != 0) {\r
+ if (HttpInstance->CacheBody != NULL) {\r
+ FreePool (HttpInstance->CacheBody);\r
+ }\r
+ \r
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);\r
+ if (HttpInstance->CacheBody == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error2;\r
+ }\r
+ \r
+ CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);\r
+ HttpInstance->CacheOffset = 0;\r
+\r
+ HttpInstance->NextMsg = HttpInstance->CacheBody + ((UINTN) HttpInstance->NextMsg - (UINTN) (Fragment.Bulk + HttpMsg->BodyLength));\r
+ }\r
+ } else {\r
+ HttpMsg->BodyLength = MIN (Fragment.Len, (UINT32) HttpMsg->BodyLength);\r
+ CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);\r
+ HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;\r
+ if (HttpInstance->CacheLen != 0) {\r
+ if (HttpInstance->CacheBody != NULL) {\r
+ FreePool (HttpInstance->CacheBody);\r
+ }\r
+ \r
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);\r
+ if (HttpInstance->CacheBody == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error2;\r
+ }\r
+\r
+ CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);\r
+ HttpInstance->CacheOffset = 0;\r
+ }\r
+ }\r
+\r
+ if (Fragment.Bulk != NULL) {\r
+ FreePool (Fragment.Bulk);\r
+ Fragment.Bulk = NULL;\r
+ }\r
+\r
+ goto Exit;\r
}\r
\r
- FreePool (Wrap);\r
return Status;\r
\r
Exit:\r
return Status;\r
\r
Error2:\r
- NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
+ if (ValueInItem != NULL) {\r
+ NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem);\r
+ }\r
\r
Error:\r
- HttpTcpTokenCleanup (Wrap);\r
+ Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken);\r
+ if (Item != NULL) {\r
+ NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
+ }\r
+\r
+ if (!HttpInstance->UseHttps) {\r
+ HttpTcpTokenCleanup (Wrap);\r
+ } else {\r
+ FreePool (Wrap);\r
+ }\r
\r
if (HttpHeaders != NULL) {\r
FreePool (HttpHeaders);\r
+ HttpHeaders = NULL;\r
+ }\r
+\r
+ if (Fragment.Bulk != NULL) {\r
+ FreePool (Fragment.Bulk);\r
+ Fragment.Bulk = NULL;\r
}\r
\r
if (HttpMsg->Headers != NULL) {\r
FreePool (HttpMsg->Headers);\r
+ HttpMsg->Headers = NULL;\r
}\r
\r
if (HttpInstance->CacheBody != NULL) {\r
Wrap->HttpInstance = HttpInstance;\r
Wrap->HttpToken = Token;\r
\r
- Status = HttpCreateTcpRxEvent (Wrap);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
+ //\r
+ // Notes: For Https, receive token wrapped in HTTP_TOKEN_WRAP is not used to \r
+ // receive the https response. A special TlsRxToken is used for receiving TLS \r
+ // related messages. It should be a blocking response.\r
+ //\r
+ if (!HttpInstance->UseHttps) {\r
+ Status = HttpCreateTcpRxEvent (Wrap);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
}\r
\r
Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);\r