HTTP_PROTOCOL *HttpInstance;\r
BOOLEAN Configure;\r
BOOLEAN ReConfigure;\r
+ BOOLEAN TlsConfigure;\r
CHAR8 *RequestMsg;\r
CHAR8 *Url;\r
UINTN UrlLen;\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
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
+ // 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
+ HttpInstance->TlsChildHandle = TlsCreateChild (\r
+ HttpInstance->Service->ImageHandle,\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
} 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
\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
\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
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
// 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 Error2;\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 - (CHAR8 *) 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 - (CHAR8 *) (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
- \r
- HttpTcpTokenCleanup (Wrap);\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