/** @file\r
Implementation of EFI_HTTP_PROTOCOL protocol interfaces.\r
\r
- Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
- (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
+ Copyright (c) 2015 - 2018, 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
are licensed and made available under the terms and conditions of the BSD License\r
\r
@param[in] This Pointer to EFI_HTTP_PROTOCOL instance.\r
@param[out] HttpConfigData Point to buffer for operational parameters of this\r
- HTTP instance.\r
+ HTTP instance. It is the responsibility of the caller\r
+ to allocate the memory for HttpConfigData and\r
+ HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact,\r
+ it is recommended to allocate sufficient memory to record\r
+ IPv6Node since it is big enough for all possibilities.\r
\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
- HttpInstance->LocalAddressIsIPv6 is FALSE and\r
- HttpConfigData->IPv4Node is NULL.\r
- HttpInstance->LocalAddressIsIPv6 is TRUE and\r
- HttpConfigData->IPv6Node is NULL.\r
+ HttpConfigData->AccessPoint.IPv4Node or\r
+ HttpConfigData->AccessPoint.IPv6Node is NULL.\r
@retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started.\r
\r
**/\r
}\r
\r
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
- ASSERT (HttpInstance != NULL);\r
\r
- if ((HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
- (!HttpInstance->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)) {\r
+ if ((HttpConfigData->AccessPoint.IPv6Node == NULL) ||\r
+ (HttpConfigData->AccessPoint.IPv4Node == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\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->AccessPoint.IPv4Node is NULL.\r
HttpConfigData->LocalAddressIsIPv6 is TRUE and\r
- HttpConfigData->IPv6Node is NULL.\r
+ HttpConfigData->AccessPoint.IPv6Node is NULL.\r
@retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling\r
Configure() with NULL to reset it.\r
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
EFIAPI\r
EfiHttpConfigure (\r
IN EFI_HTTP_PROTOCOL *This,\r
- IN EFI_HTTP_CONFIG_DATA *HttpConfigData\r
- ) \r
+ IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL\r
+ )\r
{\r
HTTP_PROTOCOL *HttpInstance;\r
EFI_STATUS Status;\r
- \r
+\r
//\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
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
- ASSERT (HttpInstance != NULL && HttpInstance->Service != NULL);\r
+ ASSERT (HttpInstance->Service != NULL);\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
HttpInstance->HttpVersion = HttpConfigData->HttpVersion;\r
HttpInstance->TimeOutMillisec = HttpConfigData->TimeOutMillisec;\r
HttpInstance->LocalAddressIsIPv6 = HttpConfigData->LocalAddressIsIPv6;\r
- \r
- if (HttpConfigData->LocalAddressIsIPv6) { \r
+\r
+ if (HttpConfigData->LocalAddressIsIPv6) {\r
CopyMem (\r
&HttpInstance->Ipv6Node,\r
HttpConfigData->AccessPoint.IPv6Node,\r
sizeof (HttpInstance->IPv4Node)\r
);\r
}\r
+\r
//\r
// Creat Tcp child\r
//\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- \r
+\r
HttpInstance->State = HTTP_STATE_HTTP_CONFIGED;\r
return EFI_SUCCESS;\r
\r
return EFI_SUCCESS;\r
}\r
}\r
- \r
+\r
\r
/**\r
The Request() function queues an HTTP request to this HTTP instance.\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
- CHAR8 *RequestStr;\r
+ BOOLEAN TlsConfigure;\r
+ CHAR8 *RequestMsg;\r
CHAR8 *Url;\r
UINTN UrlLen;\r
CHAR16 *HostNameStr;\r
HTTP_TOKEN_WRAP *Wrap;\r
CHAR8 *FileUrl;\r
- \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
}\r
\r
HttpMsg = Token->Message;\r
- if ((HttpMsg == NULL) || (HttpMsg->Headers == NULL)) {\r
+ if (HttpMsg == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- //\r
- // Current implementation does not support POST/PUT method.\r
- // If future version supports these two methods, Request could be NULL for a special case that to send large amounts\r
- // of data. For this case, the implementation need check whether previous call to Request() has been completed or not.\r
- // \r
- //\r
Request = HttpMsg->Data.Request;\r
- if ((Request == NULL) || (Request->Url == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
\r
//\r
- // Only support GET and HEAD method in current implementation.\r
+ // Only support GET, HEAD, DELETE, PATCH, PUT and POST method in current implementation.\r
//\r
- if ((Request->Method != HttpMethodGet) && (Request->Method != HttpMethodHead)) {\r
+ if ((Request != NULL) && (Request->Method != HttpMethodGet) &&\r
+ (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodDelete) &&\r
+ (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost) &&\r
+ (Request->Method != HttpMethodPatch)) {\r
return EFI_UNSUPPORTED;\r
}\r
\r
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
- ASSERT (HttpInstance != NULL);\r
+\r
+ //\r
+ // Capture the method into HttpInstance.\r
+ //\r
+ if (Request != NULL) {\r
+ HttpInstance->Method = Request->Method;\r
+ }\r
\r
if (HttpInstance->State < HTTP_STATE_HTTP_CONFIGED) {\r
return EFI_NOT_STARTED;\r
}\r
\r
- //\r
- // Check whether the token already existed.\r
- //\r
- if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTokenExist, Token))) {\r
- return EFI_ACCESS_DENIED; \r
- } \r
+ if (Request == NULL) {\r
+ //\r
+ // Request would be NULL only for PUT/POST/PATCH operation (in the current implementation)\r
+ //\r
+ if ((HttpInstance->Method != HttpMethodPut) &&\r
+ (HttpInstance->Method != HttpMethodPost) &&\r
+ (HttpInstance->Method != HttpMethodPatch)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
\r
- HostName = NULL;\r
- Wrap = NULL;\r
- HostNameStr = NULL;\r
+ //\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
- // Parse the URI of the remote host.\r
- //\r
- Url = HttpInstance->Url;\r
- UrlLen = StrLen (Request->Url) + 1;\r
- if (UrlLen > HTTP_URL_BUFFER_LEN) {\r
- Url = AllocateZeroPool (UrlLen);\r
- if (Url == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
+ //\r
+ // We need to have the Message Body for sending the HTTP message across in these cases.\r
+ //\r
+ if (HttpMsg->Body == NULL || HttpMsg->BodyLength == 0) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
- FreePool (HttpInstance->Url);\r
- HttpInstance->Url = Url; \r
- } \r
\r
+ //\r
+ // Use existing TCP instance to transmit the packet.\r
+ //\r
+ Configure = FALSE;\r
+ ReConfigure = FALSE;\r
+ } else {\r
+ //\r
+ // Check whether the token already existed.\r
+ //\r
+ if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTokenExist, Token))) {\r
+ return EFI_ACCESS_DENIED;\r
+ }\r
\r
- UnicodeStrToAsciiStr (Request->Url, Url);\r
- UrlParser = NULL;\r
- Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
- if (EFI_ERROR (Status)) {\r
- goto Error1;\r
- }\r
+ //\r
+ // Parse the URI of the remote host.\r
+ //\r
+ Url = HttpInstance->Url;\r
+ UrlLen = StrLen (Request->Url) + 1;\r
+ if (UrlLen > HTTP_URL_BUFFER_LEN) {\r
+ Url = AllocateZeroPool (UrlLen);\r
+ if (Url == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ FreePool (HttpInstance->Url);\r
+ HttpInstance->Url = Url;\r
+ }\r
\r
- RequestStr = NULL;\r
- HostName = NULL;\r
- Status = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
- if (EFI_ERROR (Status)) {\r
- goto Error1;\r
- }\r
\r
- Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
- if (EFI_ERROR (Status)) {\r
- RemotePort = HTTP_DEFAULT_PORT;\r
- }\r
- //\r
- // If Configure is TRUE, it indicates the first time to call Request();\r
- // If ReConfigure is TRUE, it indicates the request URL is not same\r
- // with the previous call to Request();\r
- //\r
- Configure = TRUE;\r
- ReConfigure = TRUE; \r
+ UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);\r
\r
- if (HttpInstance->RemoteHost == NULL) {\r
//\r
- // Request() is called the first time. \r
+ // From the information in Url, the HTTP instance will\r
+ // be able to determine whether to use http or https.\r
//\r
- ReConfigure = FALSE;\r
- } else {\r
- if ((HttpInstance->RemotePort == RemotePort) &&\r
- (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\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
- // Host Name and port number of the request URL are the same with previous call to Request().\r
- // Check whether previous TCP packet sent out.\r
+ // Use TlsSb to create Tls child and open the TLS protocol.\r
//\r
- if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTcpNotReady, NULL))) {\r
- //\r
- // Wrap the HTTP token in HTTP_TOKEN_WRAP\r
- //\r
- Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
- if (Wrap == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto Error1;\r
- }\r
+ if (HttpInstance->LocalAddressIsIPv6) {\r
+ ImageHandle = HttpInstance->Service->Ip6DriverBindingHandle;\r
+ } else {\r
+ ImageHandle = HttpInstance->Service->Ip4DriverBindingHandle;\r
+ }\r
\r
- Wrap->HttpToken = Token;\r
- Wrap->HttpInstance = HttpInstance;\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
- Status = HttpCreateTcpTxEvent (Wrap);\r
- if (EFI_ERROR (Status)) {\r
- goto Error1;\r
- }\r
+ TlsConfigure = TRUE;\r
+ }\r
\r
- Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
- if (EFI_ERROR (Status)) {\r
- goto Error1;\r
- }\r
+ UrlParser = NULL;\r
+ Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error1;\r
+ }\r
\r
- Wrap->TcpWrap.Method = Request->Method;\r
+ HostName = NULL;\r
+ Status = HttpUrlGetHostName (Url, UrlParser, &HostName);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error1;\r
+ }\r
+\r
+ Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
+ if (EFI_ERROR (Status)) {\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
+ // If ReConfigure is TRUE, it indicates the request URL is not same\r
+ // with the previous call to Request();\r
+ //\r
+ Configure = TRUE;\r
+ ReConfigure = TRUE;\r
\r
- FreePool (HostName);\r
- \r
+ if (HttpInstance->RemoteHost == NULL) {\r
+ //\r
+ // Request() is called the first time.\r
+ //\r
+ ReConfigure = FALSE;\r
+ } else {\r
+ if ((HttpInstance->RemotePort == RemotePort) &&\r
+ (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) &&\r
+ (!HttpInstance->UseHttps || (HttpInstance->UseHttps &&\r
+ !TlsConfigure &&\r
+ HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring))) {\r
//\r
- // Queue the HTTP token and return.\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
- return EFI_SUCCESS;\r
+\r
+ if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens, HttpTcpNotReady, NULL))) {\r
+ //\r
+ // Wrap the HTTP token in HTTP_TOKEN_WRAP\r
+ //\r
+ Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\r
+ if (Wrap == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error1;\r
+ }\r
+\r
+ Wrap->HttpToken = Token;\r
+ Wrap->HttpInstance = HttpInstance;\r
+\r
+ Status = HttpCreateTcpTxEvent (Wrap);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error1;\r
+ }\r
+\r
+ Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error1;\r
+ }\r
+\r
+ Wrap->TcpWrap.Method = Request->Method;\r
+\r
+ FreePool (HostName);\r
+\r
+ HttpUrlFreeParser (UrlParser);\r
+\r
+ //\r
+ // Queue the HTTP token and return.\r
+ //\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ //\r
+ // Use existing TCP instance to transmit the packet.\r
+ //\r
+ Configure = FALSE;\r
+ ReConfigure = FALSE;\r
+ }\r
} else {\r
//\r
- // Use existing TCP instance to transmit the packet.\r
+ // Need close existing TCP instance and create a new TCP instance for data transmit.\r
//\r
- Configure = FALSE;\r
- ReConfigure = FALSE;\r
- }\r
- } else {\r
- //\r
- // Need close existing TCP instance and create a new TCP instance for data transmit.\r
- //\r
- if (HttpInstance->RemoteHost != NULL) {\r
- FreePool (HttpInstance->RemoteHost);\r
- HttpInstance->RemoteHost = NULL;\r
- HttpInstance->RemotePort = 0;\r
+ if (HttpInstance->RemoteHost != NULL) {\r
+ FreePool (HttpInstance->RemoteHost);\r
+ HttpInstance->RemoteHost = NULL;\r
+ HttpInstance->RemotePort = 0;\r
+ }\r
}\r
}\r
- } \r
+ }\r
\r
if (Configure) {\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
+\r
+ AsciiStrToUnicodeStrS (HostName, HostNameStr, HostNameSize);\r
if (!HttpInstance->LocalAddressIsIPv6) {\r
Status = HttpDns4 (HttpInstance, HostNameStr, &HttpInstance->RemoteAddr);\r
} else {\r
Status = HttpDns6 (HttpInstance, HostNameStr, &HttpInstance->RemoteIpv6Addr);\r
}\r
- \r
+\r
FreePool (HostNameStr);\r
if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "Error: Could not retrieve the host address from DNS server.\n"));\r
goto Error1;\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
\r
Wrap->HttpToken = Token;\r
Wrap->HttpInstance = HttpInstance;\r
- Wrap->TcpWrap.Method = Request->Method;\r
+ if (Request != NULL) {\r
+ Wrap->TcpWrap.Method = Request->Method;\r
+ }\r
\r
- Status = HttpInitTcp (HttpInstance, Wrap, Configure);\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
+ // For the new HTTP token, create TX TCP token events.\r
//\r
Status = HttpCreateTcpTxEvent (Wrap);\r
if (EFI_ERROR (Status)) {\r
goto Error1;\r
}\r
}\r
- \r
+\r
//\r
// Create request message.\r
//\r
FileUrl = Url;\r
- if (*FileUrl != '/') {\r
+ if (Url != NULL && *FileUrl != '/') {\r
//\r
// Convert the absolute-URI to the absolute-path\r
//\r
goto Error3;\r
}\r
}\r
- RequestStr = HttpGenRequestString (HttpInstance, HttpMsg, FileUrl);\r
- if (RequestStr == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
+\r
+ Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize);\r
+\r
+ if (EFI_ERROR (Status) || NULL == RequestMsg) {\r
goto Error3;\r
}\r
\r
- Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
- if (EFI_ERROR (Status)) {\r
- goto Error4;\r
+ //\r
+ // Every request we insert a TxToken and a response call would remove the TxToken.\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
+ if (Request != NULL) {\r
+ Status = NetMapInsertTail (&HttpInstance->TxTokens, Token, Wrap);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error4;\r
+ }\r
}\r
\r
//\r
Status = HttpTransmitTcp (\r
HttpInstance,\r
Wrap,\r
- (UINT8*) RequestStr,\r
- AsciiStrLen (RequestStr)\r
+ (UINT8*) RequestMsg,\r
+ RequestMsgSize\r
);\r
if (EFI_ERROR (Status)) {\r
- goto Error5; \r
+ goto Error5;\r
}\r
\r
DispatchDpc ();\r
- \r
+\r
if (HostName != NULL) {\r
FreePool (HostName);\r
}\r
- \r
+\r
+ if (UrlParser != NULL) {\r
+ HttpUrlFreeParser (UrlParser);\r
+ }\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
Error4:\r
- if (RequestStr != NULL) {\r
- FreePool (RequestStr);\r
- } \r
+ if (RequestMsg != NULL) {\r
+ FreePool (RequestMsg);\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
if (Wrap != NULL) {\r
FreePool (Wrap);\r
}\r
- if (UrlParser!= NULL) {\r
+ if (UrlParser != NULL) {\r
HttpUrlFreeParser (UrlParser);\r
}\r
\r
return Status;\r
- \r
+\r
}\r
\r
/**\r
- Cancel a user's Token. \r
- \r
+ Cancel a user's Token.\r
+\r
@param[in] Map The HTTP instance's token queue.\r
@param[in] Item Object container for one HTTP token and token's wrap.\r
@param[in] Context The user's token to cancel.\r
IN VOID *Context\r
)\r
{\r
-\r
EFI_HTTP_TOKEN *Token;\r
HTTP_TOKEN_WRAP *Wrap;\r
HTTP_PROTOCOL *HttpInstance;\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
return EFI_ABORTED;\r
}\r
\r
- return EFI_SUCCESS; \r
+ return EFI_SUCCESS;\r
}\r
\r
/**\r
cancelled.\r
\r
@retval EFI_SUCCESS The token is cancelled.\r
- @retval EFI_NOT_FOUND The asynchronous request or response token is not found. \r
+ @retval EFI_NOT_FOUND The asynchronous request or response token is not found.\r
@retval Others Other error as indicated.\r
\r
**/\r
if (Token != NULL) {\r
if (Status == EFI_ABORTED) {\r
return EFI_SUCCESS;\r
- } \r
+ }\r
} else {\r
return Status;\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
\r
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
- ASSERT (HttpInstance != NULL);\r
\r
if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
return EFI_NOT_STARTED;\r
} else {\r
Wrap->HttpInstance->NextMsg = NULL;\r
}\r
- \r
+\r
\r
//\r
// Free Tx4Token or Tx6Token since already received corrsponding HTTP response.\r
\r
@retval EFI_SUCCESS Allocation succeeded.\r
@retval EFI_OUT_OF_RESOURCES Failed to complete the opration due to lack of resources.\r
- @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or \r
+ @retval EFI_NOT_READY Can't find a corresponding Tx4Token/Tx6Token or\r
the EFI_HTTP_UTILITIES_PROTOCOL is not available.\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
}\r
- \r
+\r
HttpInstance = Wrap->HttpInstance;\r
Token = Wrap->HttpToken;\r
HttpMsg = Token->Message;\r
SizeofHeaders = 0;\r
BufferSize = 0;\r
EndofHeader = 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
+ ValueInItem = NULL;\r
+ Fragment.Len = 0;\r
+ Fragment.Bulk = NULL;\r
\r
+ if (HttpMsg->Data.Response != NULL) {\r
//\r
// Check whether we have cached header from previous call.\r
//\r
//\r
// Check whether we cached the whole HTTP headers.\r
//\r
- EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR); \r
- } \r
+ EndofHeader = AsciiStrStr (HttpHeaders, HTTP_END_OF_HDR_STR);\r
+ }\r
\r
HttpInstance->EndofHeader = &EndofHeader;\r
HttpInstance->HttpHeaders = &HttpHeaders;\r
\r
- Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize);\r
+\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 Error;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Start the timer, and wait Timeout seconds to receive the header 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
+\r
+ Status = HttpTcpReceiveHeader (HttpInstance, &SizeofHeaders, &BufferSize, HttpInstance->TimeoutEvent);\r
+\r
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+\r
if (EFI_ERROR (Status)) {\r
goto Error;\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
- goto Error;\r
- }\r
-\r
- Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);\r
- SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);\r
- HeaderTmp = AllocateZeroPool (SizeofHeaders);\r
- if (HeaderTmp == NULL) {\r
- goto Error;\r
- }\r
-\r
- CopyMem (HeaderTmp, Tmp, SizeofHeaders);\r
- FreePool (HttpHeaders);\r
- HttpHeaders = HeaderTmp;\r
-\r
- //\r
- // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.\r
- //\r
- if (mHttpUtilities == NULL) {\r
Status = EFI_NOT_READY;\r
goto Error;\r
}\r
- \r
+\r
//\r
- // Parse the HTTP header into array of key/value pairs.\r
+ // We could have response with just a HTTP message and no headers. For Example,\r
+ // "100 Continue". In such cases, we would not want to unnecessarily call a Parse\r
+ // method. A "\r\n" following Tmp string again would indicate an end. Compare and\r
+ // set SizeofHeaders to 0.\r
//\r
- Status = mHttpUtilities->Parse (\r
- mHttpUtilities, \r
- HttpHeaders, \r
- SizeofHeaders, \r
- &HttpMsg->Headers, \r
- &HttpMsg->HeaderCount\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
+ Tmp = Tmp + AsciiStrLen (HTTP_CRLF_STR);\r
+ if (CompareMem (Tmp, HTTP_CRLF_STR, AsciiStrLen (HTTP_CRLF_STR)) == 0) {\r
+ SizeofHeaders = 0;\r
+ } else {\r
+ SizeofHeaders = SizeofHeaders - (Tmp - HttpHeaders);\r
}\r
\r
- FreePool (HttpHeaders);\r
- HttpHeaders = NULL;\r
- \r
HttpMsg->Data.Response->StatusCode = HttpMappingToStatusCode (StatusCode);\r
+ HttpInstance->StatusCode = StatusCode;\r
\r
- //\r
- // Init message-body parser by header information. \r
- //\r
Status = EFI_NOT_READY;\r
ValueInItem = NULL;\r
- NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);\r
- if (ValueInItem == NULL) {\r
- goto Error;\r
- }\r
\r
//\r
- // The first Tx Token not transmitted yet, insert back and return error.\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
+ // Hence, check that case before doing a NetMapRemoveHead.\r
//\r
- if (!ValueInItem->TcpWrap.IsTxDone) {\r
- goto Error2;\r
- }\r
+ if (!NetMapIsEmpty (&HttpInstance->TxTokens)) {\r
+ NetMapRemoveHead (&HttpInstance->TxTokens, (VOID**) &ValueInItem);\r
+ if (ValueInItem == NULL) {\r
+ goto Error;\r
+ }\r
\r
- Status = HttpInitMsgParser (\r
- ValueInItem->TcpWrap.Method,\r
- HttpMsg->Data.Response->StatusCode,\r
- HttpMsg->HeaderCount,\r
- HttpMsg->Headers,\r
- HttpBodyParserCallback,\r
- (VOID *) ValueInItem,\r
- &HttpInstance->MsgParser\r
- );\r
- if (EFI_ERROR (Status)) { \r
- goto Error2;\r
+ //\r
+ // The first Tx Token not transmitted yet, insert back and return error.\r
+ //\r
+ if (!ValueInItem->TcpWrap.IsTxDone) {\r
+ goto Error2;\r
+ }\r
}\r
\r
- //\r
- // Check whether we received a complete HTTP message.\r
- //\r
- if (HttpInstance->CacheBody != NULL) {\r
- Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);\r
+ if (SizeofHeaders != 0) {\r
+ HeaderTmp = AllocateZeroPool (SizeofHeaders);\r
+ if (HeaderTmp == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Error2;\r
+ }\r
+\r
+ CopyMem (HeaderTmp, Tmp, SizeofHeaders);\r
+ FreePool (HttpHeaders);\r
+ HttpHeaders = HeaderTmp;\r
+\r
+ //\r
+ // Check whether the EFI_HTTP_UTILITIES_PROTOCOL is available.\r
+ //\r
+ if (mHttpUtilities == NULL) {\r
+ Status = EFI_NOT_READY;\r
+ goto Error2;\r
+ }\r
+\r
+ //\r
+ // Parse the HTTP header into array of key/value pairs.\r
+ //\r
+ Status = mHttpUtilities->Parse (\r
+ mHttpUtilities,\r
+ HttpHeaders,\r
+ SizeofHeaders,\r
+ &HttpMsg->Headers,\r
+ &HttpMsg->HeaderCount\r
+ );\r
if (EFI_ERROR (Status)) {\r
goto Error2;\r
}\r
\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
+ FreePool (HttpHeaders);\r
+ HttpHeaders = NULL;\r
+\r
+\r
+ //\r
+ // Init message-body parser by header information.\r
+ //\r
+ Status = HttpInitMsgParser (\r
+ HttpInstance->Method,\r
+ HttpMsg->Data.Response->StatusCode,\r
+ HttpMsg->HeaderCount,\r
+ HttpMsg->Headers,\r
+ HttpBodyParserCallback,\r
+ (VOID *) ValueInItem,\r
+ &HttpInstance->MsgParser\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
+\r
+ //\r
+ // Check whether we received a complete HTTP message.\r
+ //\r
+ if (HttpInstance->CacheBody != NULL) {\r
+ Status = HttpParseMessageBody (HttpInstance->MsgParser, HttpInstance->CacheLen, HttpInstance->CacheBody);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
+\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
}\r
\r
- if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) { \r
+ if ((HttpMsg->Body == NULL) || (HttpMsg->BodyLength == 0)) {\r
Status = EFI_SUCCESS;\r
goto Exit;\r
}\r
- } \r
+ }\r
\r
//\r
// Receive the response body.\r
//\r
// We have a cached HTTP message which includes a part of HTTP header of next message.\r
//\r
- BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset); \r
+ BodyLen = HttpInstance->NextMsg - (HttpInstance->CacheBody + HttpInstance->CacheOffset);\r
} else {\r
BodyLen = HttpInstance->CacheLen - HttpInstance->CacheOffset;\r
}\r
//\r
Status = EFI_SUCCESS;\r
goto Exit;\r
- } \r
+ }\r
\r
if (BodyLen == 0 && HttpInstance->MsgParser == NULL) {\r
//\r
//\r
HttpMsg->BodyLength = 0;\r
Status = EFI_SUCCESS;\r
- goto Exit; \r
- } \r
+ goto Exit;\r
+ }\r
}\r
\r
ASSERT (HttpInstance->MsgParser != NULL);\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);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\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
+ // 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 Error2;\r
+ }\r
+\r
+ Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance->TimeoutEvent);\r
+\r
+ gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error2;\r
+ }\r
+\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
+ 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
+ //\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
return Status;\r
if (Item != NULL) {\r
NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
}\r
- Token->Status = Status;\r
+\r
+ if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {\r
+ Token->Status = EFI_HTTP_ERROR;\r
+ } else {\r
+ Token->Status = Status;\r
+ }\r
+\r
gBS->SignalEvent (Token->Event);\r
HttpCloseTcpRxEvent (Wrap);\r
FreePool (Wrap);\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
- \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
HttpInstance->CacheBody = NULL;\r
}\r
\r
- Token->Status = Status;\r
+ if (HttpInstance->StatusCode >= HTTP_ERROR_OR_NOT_SUPPORT_STATUS_CODE) {\r
+ Token->Status = EFI_HTTP_ERROR;\r
+ } else {\r
+ Token->Status = Status;\r
+ }\r
+\r
gBS->SignalEvent (Token->Event);\r
\r
- return Status; \r
+ return Status;\r
\r
}\r
\r
if (HttpMsg == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
- ASSERT (HttpInstance != NULL);\r
\r
if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
return EFI_NOT_STARTED;\r
// Check whether the token already existed.\r
//\r
if (EFI_ERROR (NetMapIterate (&HttpInstance->RxTokens, HttpTokenExist, Token))) {\r
- return EFI_ACCESS_DENIED; \r
+ return EFI_ACCESS_DENIED;\r
}\r
\r
Wrap = AllocateZeroPool (sizeof (HTTP_TOKEN_WRAP));\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
gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event);\r
}\r
FreePool (Wrap);\r
- } \r
+ }\r
\r
- return Status; \r
+ return Status;\r
}\r
\r
/**\r
}\r
\r
HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This);\r
- ASSERT (HttpInstance != NULL);\r
\r
if (HttpInstance->State != HTTP_STATE_TCP_CONNECTED) {\r
return EFI_NOT_STARTED;\r
}\r
- \r
+\r
if (HttpInstance->LocalAddressIsIPv6) {\r
if (HttpInstance->Tcp6 == NULL) {\r
return EFI_NOT_STARTED;\r
}\r
Status = HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);\r
}\r
- \r
+\r
DispatchDpc ();\r
- \r
+\r
return Status;\r
}\r