summaryrefslogtreecommitdiff
path: root/NetworkPkg/HttpDxe/HttpImpl.c
diff options
context:
space:
mode:
authorJiaxin Wu <jiaxin.wu@intel.com>2016-12-14 10:57:41 +0800
committerJiaxin Wu <jiaxin.wu@intel.com>2016-12-22 20:33:40 +0800
commitdac45de3d6afd6da19c192a65ad8493f513fd1be (patch)
tree01da1481e738ee222f404d79fdfcc5f4fc473408 /NetworkPkg/HttpDxe/HttpImpl.c
parent9d0fa533dd0136a06d076bc6eee1462499a4a936 (diff)
downloadedk2-platforms-dac45de3d6afd6da19c192a65ad8493f513fd1be.tar.xz
NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6
This patch is used to enable HTTPS feature. HttpDxe driver will consume TlsDxe driver. It can both support http and https feature, that’s depended on the information of URL, the HTTP instance can be able to determine whether to use http or https. Cc: Ye Ting <ting.ye@intel.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Cc: Zhang Lubo <lubo.zhang@intel.com> Cc: Long Qin <qin.long@intel.com> Cc: Thomas Palmer <thomas.palmer@hpe.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com>
Diffstat (limited to 'NetworkPkg/HttpDxe/HttpImpl.c')
-rw-r--r--NetworkPkg/HttpDxe/HttpImpl.c252
1 files changed, 218 insertions, 34 deletions
diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c
index 6fcb0b7c6e..77aa64a2b9 100644
--- a/NetworkPkg/HttpDxe/HttpImpl.c
+++ b/NetworkPkg/HttpDxe/HttpImpl.c
@@ -241,6 +241,7 @@ EfiHttpRequest (
HTTP_PROTOCOL *HttpInstance;
BOOLEAN Configure;
BOOLEAN ReConfigure;
+ BOOLEAN TlsConfigure;
CHAR8 *RequestMsg;
CHAR8 *Url;
UINTN UrlLen;
@@ -260,6 +261,7 @@ EfiHttpRequest (
HostNameStr = NULL;
Wrap = NULL;
FileUrl = NULL;
+ TlsConfigure = FALSE;
if ((This == NULL) || (Token == NULL)) {
return EFI_INVALID_PARAMETER;
@@ -345,6 +347,32 @@ EfiHttpRequest (
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);
+
+ //
+ // 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.
+ //
+ HttpInstance->TlsChildHandle = TlsCreateChild (
+ HttpInstance->Service->ImageHandle,
+ &(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)) {
@@ -359,7 +387,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();
@@ -376,9 +408,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.
//
@@ -482,6 +518,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);
}
@@ -500,13 +546,18 @@ EfiHttpRequest (
if (Request != NULL) {
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.
//
@@ -593,9 +644,14 @@ Error4:
}
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);
@@ -731,22 +787,30 @@ HttpCancel (
}
}
- //
- // 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);
}
}
-
+
return EFI_SUCCESS;
}
@@ -882,6 +946,7 @@ HttpResponseWorker (
NET_MAP_ITEM *Item;
HTTP_TOKEN_WRAP *ValueInItem;
UINTN HdrLen;
+ NET_FRAGMENT Fragment;
if (Wrap == NULL || Wrap->HttpInstance == NULL) {
return EFI_INVALID_PARAMETER;
@@ -899,17 +964,11 @@ HttpResponseWorker (
BufferSize = 0;
EndofHeader = NULL;
ValueInItem = NULL;
+ Fragment.Len = 0;
+ Fragment.Bulk = NULL;
if (HttpMsg->Data.Response != NULL) {
//
- // Need receive the HTTP headers, prepare buffer.
- //
- Status = HttpCreateTcpRxEventForHeader (HttpInstance);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
-
- //
// Check whether we have cached header from previous call.
//
if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg != NULL)) {
@@ -1200,9 +1259,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 - (CHAR8 *) 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 - (CHAR8 *) (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;
@@ -1234,15 +1400,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) {
@@ -1353,9 +1530,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);