X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FHttpDxe%2FHttpImpl.c;h=f70e116f38d7e78f7bfc131c343b26aa4bc622bc;hb=c6a14de3ef30291918f3b15436cf6a75db413eea;hp=ad194dbe0e5556da82d703477302082d690ff3c6;hpb=30526a51dda7e8db483f22a045f32f3a18eea5c7;p=mirror_edk2.git
diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
index ad194dbe0e..f70e116f38 100644
--- a/NetworkPkg/HttpDxe/HttpImpl.c
+++ b/NetworkPkg/HttpDxe/HttpImpl.c
@@ -1,7 +1,7 @@
/** @file
Implementation of EFI_HTTP_PROTOCOL protocol interfaces.
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
This program and the accompanying materials
@@ -33,16 +33,18 @@ EFI_HTTP_PROTOCOL mEfiHttpTemplate = {
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.
@param[out] HttpConfigData Point to buffer for operational parameters of this
- HTTP instance.
+ HTTP instance. It is the responsibility of the caller
+ to allocate the memory for HttpConfigData and
+ HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact,
+ it is recommended to allocate sufficient memory to record
+ IPv6Node since it is big enough for all possibilities.
@retval EFI_SUCCESS Operation succeeded.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
HttpConfigData is NULL.
- HttpInstance->LocalAddressIsIPv6 is FALSE and
- HttpConfigData->IPv4Node is NULL.
- HttpInstance->LocalAddressIsIPv6 is TRUE and
- HttpConfigData->IPv6Node is NULL.
+ HttpConfigData->AccessPoint.IPv4Node or
+ HttpConfigData->AccessPoint.IPv6Node is NULL.
@retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.
**/
@@ -63,10 +65,9 @@ EfiHttpGetModeData (
}
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
- ASSERT (HttpInstance != NULL);
- if ((HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||
- (!HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)) {
+ if ((HttpConfigData->AccessPoint.IPv6Node == NULL) ||
+ (HttpConfigData->AccessPoint.IPv4Node == NULL)) {
return EFI_INVALID_PARAMETER;
}
@@ -115,9 +116,9 @@ EfiHttpGetModeData (
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
This is NULL.
HttpConfigData->LocalAddressIsIPv6 is FALSE and
- HttpConfigData->IPv4Node is NULL.
+ HttpConfigData->AccessPoint.IPv4Node is NULL.
HttpConfigData->LocalAddressIsIPv6 is TRUE and
- HttpConfigData->IPv6Node is NULL.
+ HttpConfigData->AccessPoint.IPv6Node is NULL.
@retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling
Configure() with NULL to reset it.
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
@@ -130,27 +131,31 @@ EFI_STATUS
EFIAPI
EfiHttpConfigure (
IN EFI_HTTP_PROTOCOL *This,
- IN EFI_HTTP_CONFIG_DATA *HttpConfigData
- )
+ IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL
+ )
{
HTTP_PROTOCOL *HttpInstance;
EFI_STATUS Status;
-
+
//
// Check input parameters.
//
if (This == NULL ||
- (HttpConfigData != NULL &&
+ (HttpConfigData != NULL &&
((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||
(!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) {
return EFI_INVALID_PARAMETER;
}
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
- ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);
+ ASSERT (HttpInstance->Service != NULL);
if (HttpConfigData != NULL) {
+ if (HttpConfigData->HttpVersion >= HttpVersionUnsupported) {
+ return EFI_UNSUPPORTED;
+ }
+
//
// Now configure this HTTP instance.
//
@@ -161,8 +166,8 @@ EfiHttpConfigure (
HttpInstance->HttpVersion = HttpConfigData->HttpVersion;
HttpInstance->TimeOutMillisec = HttpConfigData->TimeOutMillisec;
HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;
-
- if (HttpConfigData->LocalAddressIsIPv6) {
+
+ if (HttpConfigData->LocalAddressIsIPv6) {
CopyMem (
&HttpInstance->Ipv6Node,
HttpConfigData->AccessPoint.IPv6Node,
@@ -175,7 +180,7 @@ EfiHttpConfigure (
sizeof (HttpInstance->IPv4Node)
);
}
-
+
//
// Creat Tcp child
//
@@ -183,7 +188,7 @@ EfiHttpConfigure (
if (EFI_ERROR (Status)) {
return Status;
}
-
+
HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;
return EFI_SUCCESS;
@@ -196,7 +201,7 @@ EfiHttpConfigure (
return EFI_SUCCESS;
}
}
-
+
/**
The Request() function queues an HTTP request to this HTTP instance.
@@ -236,10 +241,12 @@ EfiHttpRequest (
VOID *UrlParser;
EFI_STATUS Status;
CHAR8 *HostName;
+ UINTN HostNameSize;
UINT16 RemotePort;
HTTP_PROTOCOL *HttpInstance;
BOOLEAN Configure;
BOOLEAN ReConfigure;
+ BOOLEAN TlsConfigure;
CHAR8 *RequestMsg;
CHAR8 *Url;
UINTN UrlLen;
@@ -247,6 +254,7 @@ EfiHttpRequest (
HTTP_TOKEN_WRAP *Wrap;
CHAR8 *FileUrl;
UINTN RequestMsgSize;
+ EFI_HANDLE ImageHandle;
//
// Initializations
@@ -259,6 +267,7 @@ EfiHttpRequest (
HostNameStr = NULL;
Wrap = NULL;
FileUrl = NULL;
+ TlsConfigure = FALSE;
if ((This == NULL) || (Token == NULL)) {
return EFI_INVALID_PARAMETER;
@@ -272,15 +281,16 @@ EfiHttpRequest (
Request = HttpMsg->Data.Request;
//
- // Only support GET, HEAD, PUT and POST method in current implementation.
+ // Only support GET, HEAD, DELETE, PATCH, PUT and POST method in current implementation.
//
if ((Request != NULL) && (Request->Method != HttpMethodGet) &&
- (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost)) {
+ (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodDelete) &&
+ (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost) &&
+ (Request->Method != HttpMethodPatch)) {
return EFI_UNSUPPORTED;
}
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
- ASSERT (HttpInstance != NULL);
//
// Capture the method into HttpInstance.
@@ -295,14 +305,16 @@ EfiHttpRequest (
if (Request == NULL) {
//
- // Request would be NULL only for PUT/POST operation (in the current implementation)
+ // Request would be NULL only for PUT/POST/PATCH operation (in the current implementation)
//
- if ((HttpInstance->Method != HttpMethodPut) && (HttpInstance->Method != HttpMethodPost)) {
+ if ((HttpInstance->Method != HttpMethodPut) &&
+ (HttpInstance->Method != HttpMethodPost) &&
+ (HttpInstance->Method != HttpMethodPatch)) {
return EFI_INVALID_PARAMETER;
}
//
- // For PUT/POST, we need to have the TCP already configured. Bail out if it is not!
+ // For PUT/POST/PATCH, we need to have the TCP already configured. Bail out if it is not!
//
if (HttpInstance->State < HTTP_STATE_TCP_CONFIGED) {
return EFI_INVALID_PARAMETER;
@@ -343,7 +355,50 @@ EfiHttpRequest (
}
- UnicodeStrToAsciiStr (Request->Url, Url);
+ UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);
+
+ //
+ // From the information in Url, the HTTP instance will
+ // be able to determine whether to use http or https.
+ //
+ HttpInstance->UseHttps = IsHttpsUrl (Url);
+
+ //
+ // HTTP is disabled, return directly if the URI is not HTTPS.
+ //
+ if (!PcdGetBool (PcdAllowHttpConnections) && !(HttpInstance->UseHttps)) {
+
+ DEBUG ((EFI_D_ERROR, "EfiHttpRequest: HTTP is disabled.\n"));
+
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check whether we need to create Tls child and open the TLS protocol.
+ //
+ if (HttpInstance->UseHttps && HttpInstance->TlsChildHandle == NULL) {
+ //
+ // Use TlsSb to create Tls child and open the TLS protocol.
+ //
+ if (HttpInstance->LocalAddressIsIPv6) {
+ ImageHandle = HttpInstance->Service->Ip6DriverBindingHandle;
+ } else {
+ ImageHandle = HttpInstance->Service->Ip4DriverBindingHandle;
+ }
+
+ HttpInstance->TlsChildHandle = TlsCreateChild (
+ ImageHandle,
+ &(HttpInstance->TlsSb),
+ &(HttpInstance->Tls),
+ &(HttpInstance->TlsConfiguration)
+ );
+ if (HttpInstance->TlsChildHandle == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ TlsConfigure = TRUE;
+ }
+
UrlParser = NULL;
Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);
if (EFI_ERROR (Status)) {
@@ -358,7 +413,11 @@ EfiHttpRequest (
Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);
if (EFI_ERROR (Status)) {
- RemotePort = HTTP_DEFAULT_PORT;
+ if (HttpInstance->UseHttps) {
+ RemotePort = HTTPS_DEFAULT_PORT;
+ } else {
+ RemotePort = HTTP_DEFAULT_PORT;
+ }
}
//
// If Configure is TRUE, it indicates the first time to call Request();
@@ -375,9 +434,13 @@ EfiHttpRequest (
ReConfigure = FALSE;
} else {
if ((HttpInstance->RemotePort == RemotePort) &&
- (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {
+ (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) &&
+ (!HttpInstance->UseHttps || (HttpInstance->UseHttps &&
+ !TlsConfigure &&
+ HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring))) {
//
// Host Name and port number of the request URL are the same with previous call to Request().
+ // If Https protocol used, the corresponding SessionState is EfiTlsSessionDataTransferring.
// Check whether previous TCP packet sent out.
//
@@ -408,6 +471,8 @@ EfiHttpRequest (
FreePool (HostName);
+ HttpUrlFreeParser (UrlParser);
+
//
// Queue the HTTP token and return.
//
@@ -430,7 +495,7 @@ EfiHttpRequest (
}
}
}
- }
+ }
if (Configure) {
//
@@ -443,21 +508,23 @@ EfiHttpRequest (
}
if (EFI_ERROR (Status)) {
- HostNameStr = AllocateZeroPool ((AsciiStrLen (HostName) + 1) * sizeof (CHAR16));
+ HostNameSize = AsciiStrSize (HostName);
+ HostNameStr = AllocateZeroPool (HostNameSize * sizeof (CHAR16));
if (HostNameStr == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error1;
}
-
- AsciiStrToUnicodeStr (HostName, HostNameStr);
+
+ AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);
if (!HttpInstance->LocalAddressIsIPv6) {
Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);
} else {
Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr);
}
-
+
FreePool (HostNameStr);
if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Error: Could not retrieve the host address from DNS server.\n"));
goto Error1;
}
}
@@ -480,6 +547,16 @@ EfiHttpRequest (
} else {
ASSERT (HttpInstance->Tcp6 != NULL);
}
+
+ if (HttpInstance->UseHttps && !TlsConfigure) {
+ Status = TlsCloseSession (HttpInstance);
+ if (EFI_ERROR (Status)) {
+ goto Error1;
+ }
+
+ TlsCloseTxRxEvent (HttpInstance);
+ }
+
HttpCloseConnection (HttpInstance);
EfiHttpCancel (This, NULL);
}
@@ -499,21 +576,26 @@ EfiHttpRequest (
Wrap->TcpWrap.Method = Request->Method;
}
- Status = HttpInitTcp (HttpInstance, Wrap, Configure);
+ Status = HttpInitSession (
+ HttpInstance,
+ Wrap,
+ Configure || ReConfigure,
+ TlsConfigure
+ );
if (EFI_ERROR (Status)) {
goto Error2;
- }
+ }
- if (!Configure) {
+ if (!Configure && !ReConfigure && !TlsConfigure) {
//
- // For the new HTTP token, create TX TCP token events.
+ // For the new HTTP token, create TX TCP token events.
//
Status = HttpCreateTcpTxEvent (Wrap);
if (EFI_ERROR (Status)) {
goto Error1;
}
}
-
+
//
// Create request message.
//
@@ -538,13 +620,13 @@ EfiHttpRequest (
Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize);
- if (EFI_ERROR (Status)) {
+ if (EFI_ERROR (Status) || NULL == RequestMsg) {
goto Error3;
}
//
// Every request we insert a TxToken and a response call would remove the TxToken.
- // In cases of PUT/POST, after an initial request-response pair, we would do a
+ // In cases of PUT/POST/PATCH, after an initial request-response pair, we would do a
// continuous request without a response call. So, in such cases, where Request
// structure is NULL, we would not insert a TxToken.
//
@@ -565,15 +647,19 @@ EfiHttpRequest (
RequestMsgSize
);
if (EFI_ERROR (Status)) {
- goto Error5;
+ goto Error5;
}
DispatchDpc ();
-
+
if (HostName != NULL) {
FreePool (HostName);
}
-
+
+ if (UrlParser != NULL) {
+ HttpUrlFreeParser (UrlParser);
+ }
+
return EFI_SUCCESS;
Error5:
@@ -588,12 +674,17 @@ Error5:
Error4:
if (RequestMsg != NULL) {
FreePool (RequestMsg);
- }
+ }
Error3:
- HttpCloseConnection (HttpInstance);
+ if (HttpInstance->UseHttps) {
+ TlsCloseSession (HttpInstance);
+ TlsCloseTxRxEvent (HttpInstance);
+ }
Error2:
+ HttpCloseConnection (HttpInstance);
+
HttpCloseTcpConnCloseEvent (HttpInstance);
if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {
gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
@@ -611,17 +702,17 @@ Error1:
if (Wrap != NULL) {
FreePool (Wrap);
}
- if (UrlParser!= NULL) {
+ if (UrlParser != NULL) {
HttpUrlFreeParser (UrlParser);
}
return Status;
-
+
}
/**
- Cancel a user's Token.
-
+ Cancel a user's Token.
+
@param[in] Map The HTTP instance's token queue.
@param[in] Item Object container for one HTTP token and token's wrap.
@param[in] Context The user's token to cancel.
@@ -655,7 +746,7 @@ HttpCancelTokens (
Wrap = (HTTP_TOKEN_WRAP *) Item->Value;
ASSERT (Wrap != NULL);
HttpInstance = Wrap->HttpInstance;
-
+
if (!HttpInstance->LocalAddressIsIPv6) {
if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) {
//
@@ -690,7 +781,7 @@ HttpCancelTokens (
return EFI_ABORTED;
}
- return EFI_SUCCESS;
+ return EFI_SUCCESS;
}
/**
@@ -703,7 +794,7 @@ HttpCancelTokens (
cancelled.
@retval EFI_SUCCESS The token is cancelled.
- @retval EFI_NOT_FOUND The asynchronous request or response token is not found.
+ @retval EFI_NOT_FOUND The asynchronous request or response token is not found.
@retval Others Other error as indicated.
**/
@@ -723,25 +814,33 @@ HttpCancel (
if (Token != NULL) {
if (Status == EFI_ABORTED) {
return EFI_SUCCESS;
- }
+ }
} else {
return Status;
}
}
- //
- // Then check the tokens queued by EfiHttpResponse().
- //
- Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);
- if (EFI_ERROR (Status)) {
- if (Token != NULL) {
- if (Status == EFI_ABORTED) {
- return EFI_SUCCESS;
+ if (!HttpInstance->UseHttps) {
+ //
+ // Then check the tokens queued by EfiHttpResponse(), except for Https.
+ //
+ Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);
+ if (EFI_ERROR (Status)) {
+ if (Token != NULL) {
+ if (Status == EFI_ABORTED) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
} else {
- return EFI_NOT_FOUND;
+ return Status;
}
+ }
+ } else {
+ if (!HttpInstance->LocalAddressIsIPv6) {
+ HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
} else {
- return Status;
+ HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
}
}
@@ -785,7 +884,6 @@ EfiHttpCancel (
}
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
- ASSERT (HttpInstance != NULL);
if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
return EFI_NOT_STARTED;
@@ -838,7 +936,7 @@ HttpBodyParserCallback (
} else {
Wrap->HttpInstance->NextMsg = NULL;
}
-
+
//
// Free Tx4Token or Tx6Token since already received corrsponding HTTP response.
@@ -855,7 +953,7 @@ HttpBodyParserCallback (
@retval EFI_SUCCESS Allocation succeeded.
@retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources.
- @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or
+ @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or
the EFI_HTTP_UTILITIES_PROTOCOL is not available.
**/
@@ -880,11 +978,12 @@ HttpResponseWorker (
NET_MAP_ITEM *Item;
HTTP_TOKEN_WRAP *ValueInItem;
UINTN HdrLen;
+ NET_FRAGMENT Fragment;
if (Wrap == NULL || Wrap->HttpInstance == NULL) {
return EFI_INVALID_PARAMETER;
}
-
+
HttpInstance = Wrap->HttpInstance;
Token = Wrap->HttpToken;
HttpMsg = Token->Message;
@@ -897,16 +996,10 @@ HttpResponseWorker (
BufferSize = 0;
EndofHeader = NULL;
ValueInItem = NULL;
-
- if (HttpMsg->Data.Response != NULL) {
- //
- // Need receive the HTTP headers, prepare buffer.
- //
- Status = HttpCreateTcpRxEventForHeader (HttpInstance);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
+ Fragment.Len = 0;
+ Fragment.Bulk = NULL;
+ if (HttpMsg->Data.Response != NULL) {
//
// Check whether we have cached header from previous call.
//
@@ -932,8 +1025,8 @@ HttpResponseWorker (
//
// Check whether we cached the whole HTTP headers.
//
- EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR);
- }
+ EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR);
+ }
HttpInstance->EndofHeader = &EndofHeader;
HttpInstance->HttpHeaders = &HttpHeaders;
@@ -1032,7 +1125,7 @@ HttpResponseWorker (
ValueInItem = NULL;
//
- // In cases of PUT/POST, after an initial request-response pair, we would do a
+ // In cases of PUT/POST/PATCH, after an initial request-response pair, we would do a
// continuous request without a response call. So, we would not do an insert of
// TxToken. After we have sent the complete file, we will call a response to get
// a final response from server. In such a case, we would not have any TxTokens.
@@ -1146,7 +1239,7 @@ HttpResponseWorker (
//
// We have a cached HTTP message which includes a part of HTTP header of next message.
//
- BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);
+ BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);
} else {
BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;
}
@@ -1181,7 +1274,7 @@ HttpResponseWorker (
//
Status = EFI_SUCCESS;
goto Exit;
- }
+ }
if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {
//
@@ -1189,8 +1282,8 @@ HttpResponseWorker (
//
HttpMsg->BodyLength = 0;
Status = EFI_SUCCESS;
- goto Exit;
- }
+ goto Exit;
+ }
}
ASSERT (HttpInstance->MsgParser != NULL);
@@ -1198,9 +1291,116 @@ HttpResponseWorker (
//
// We still need receive more data when there is no cache data and MsgParser is not NULL;
//
- Status = HttpTcpReceiveBody (Wrap, HttpMsg);
- if (EFI_ERROR (Status)) {
- goto Error2;
+ if (!HttpInstance->UseHttps) {
+ Status = HttpTcpReceiveBody (Wrap, HttpMsg);
+
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ } else {
+ if (HttpInstance->TimeoutEvent == NULL) {
+ //
+ // Create TimeoutEvent for response
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &HttpInstance->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+ }
+
+ //
+ // Start the timer, and wait Timeout seconds to receive the body packet.
+ //
+ Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance->TimeoutEvent);
+
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ //
+ // Check whether we receive a complete HTTP message.
+ //
+ Status = HttpParseMessageBody (
+ HttpInstance->MsgParser,
+ (UINTN) Fragment.Len,
+ (CHAR8 *) Fragment.Bulk
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error2;
+ }
+
+ if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
+ //
+ // Free the MsgParse since we already have a full HTTP message.
+ //
+ HttpFreeMsgParser (HttpInstance->MsgParser);
+ HttpInstance->MsgParser = NULL;
+ }
+
+ //
+ // We receive part of header of next HTTP msg.
+ //
+ if (HttpInstance->NextMsg != NULL) {
+ HttpMsg->BodyLength = MIN ((UINTN) HttpInstance->NextMsg - (UINTN) Fragment.Bulk, HttpMsg->BodyLength);
+ CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);
+
+ HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;
+ if (HttpInstance->CacheLen != 0) {
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ }
+
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
+ if (HttpInstance->CacheBody == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error2;
+ }
+
+ CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);
+ HttpInstance->CacheOffset = 0;
+
+ HttpInstance->NextMsg = HttpInstance->CacheBody + ((UINTN) HttpInstance->NextMsg - (UINTN) (Fragment.Bulk + HttpMsg->BodyLength));
+ }
+ } else {
+ HttpMsg->BodyLength = MIN (Fragment.Len, (UINT32) HttpMsg->BodyLength);
+ CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);
+ HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;
+ if (HttpInstance->CacheLen != 0) {
+ if (HttpInstance->CacheBody != NULL) {
+ FreePool (HttpInstance->CacheBody);
+ }
+
+ HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);
+ if (HttpInstance->CacheBody == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error2;
+ }
+
+ CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);
+ HttpInstance->CacheOffset = 0;
+ }
+ }
+
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
+ }
+
+ goto Exit;
}
return Status;
@@ -1232,15 +1432,26 @@ Error:
if (Item != NULL) {
NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
}
-
- HttpTcpTokenCleanup (Wrap);
-
+
+ if (!HttpInstance->UseHttps) {
+ HttpTcpTokenCleanup (Wrap);
+ } else {
+ FreePool (Wrap);
+ }
+
if (HttpHeaders != NULL) {
FreePool (HttpHeaders);
+ HttpHeaders = NULL;
+ }
+
+ if (Fragment.Bulk != NULL) {
+ FreePool (Fragment.Bulk);
+ Fragment.Bulk = NULL;
}
if (HttpMsg->Headers != NULL) {
FreePool (HttpMsg->Headers);
+ HttpMsg->Headers = NULL;
}
if (HttpInstance->CacheBody != NULL) {
@@ -1256,7 +1467,7 @@ Error:
gBS->SignalEvent (Token->Event);
- return Status;
+ return Status;
}
@@ -1328,9 +1539,8 @@ EfiHttpResponse (
if (HttpMsg == NULL) {
return EFI_INVALID_PARAMETER;
}
-
+
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
- ASSERT (HttpInstance != NULL);
if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
return EFI_NOT_STARTED;
@@ -1340,7 +1550,7 @@ EfiHttpResponse (
// Check whether the token already existed.
//
if (EFI_ERROR (NetMapIterate (&HttpInstance->RxTokens, HttpTokenExist, Token))) {
- return EFI_ACCESS_DENIED;
+ return EFI_ACCESS_DENIED;
}
Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));
@@ -1351,9 +1561,16 @@ EfiHttpResponse (
Wrap->HttpInstance = HttpInstance;
Wrap->HttpToken = Token;
- Status = HttpCreateTcpRxEvent (Wrap);
- if (EFI_ERROR (Status)) {
- goto Error;
+ //
+ // Notes: For Https, receive token wrapped in HTTP_TOKEN_WRAP is not used to
+ // receive the https response. A special TlsRxToken is used for receiving TLS
+ // related messages. It should be a blocking response.
+ //
+ if (!HttpInstance->UseHttps) {
+ Status = HttpCreateTcpRxEvent (Wrap);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
}
Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);
@@ -1380,9 +1597,9 @@ Error:
gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);
}
FreePool (Wrap);
- }
+ }
- return Status;
+ return Status;
}
/**
@@ -1419,12 +1636,11 @@ EfiHttpPoll (
}
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);
- ASSERT (HttpInstance != NULL);
if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {
return EFI_NOT_STARTED;
}
-
+
if (HttpInstance->LocalAddressIsIPv6) {
if (HttpInstance->Tcp6 == NULL) {
return EFI_NOT_STARTED;
@@ -1436,8 +1652,8 @@ EfiHttpPoll (
}
Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
}
-
+
DispatchDpc ();
-
+
return Status;
}