X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FHttpDxe%2FHttpImpl.c;h=85b00833492e52ebbaabb7bf520d3bff2325e30a;hb=221463c2b337072532ed4ab8ffe3b566574724d8;hp=dd10f826b4b4470be2a8fe9a9b24ae14c609c936;hpb=d8293d31416242468323ef30c6fa2a5bf6267996;p=mirror_edk2.git diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index dd10f826b4..85b0083349 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 - 2017, Intel Corporation. All rights reserved.
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
This program and the accompanying materials @@ -114,7 +114,6 @@ EfiHttpGetModeData ( @retval EFI_SUCCESS Operation succeeded. @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: This is NULL. - HttpConfigData is NULL. HttpConfigData->LocalAddressIsIPv6 is FALSE and HttpConfigData->IPv4Node is NULL. HttpConfigData->LocalAddressIsIPv6 is TRUE and @@ -141,9 +140,9 @@ EfiHttpConfigure ( // Check input parameters. // if (This == NULL || - HttpConfigData == NULL || - ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) || - (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL))) { + (HttpConfigData != NULL && + ((HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv6Node == NULL) || + (!HttpConfigData->LocalAddressIsIPv6 && HttpConfigData->AccessPoint.IPv4Node == NULL)))) { return EFI_INVALID_PARAMETER; } @@ -237,10 +236,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; @@ -253,11 +254,14 @@ EfiHttpRequest ( // Initializations // Url = NULL; + UrlParser = NULL; + RemotePort = 0; HostName = NULL; RequestMsg = NULL; HostNameStr = NULL; Wrap = NULL; FileUrl = NULL; + TlsConfigure = FALSE; if ((This == NULL) || (Token == NULL)) { return EFI_INVALID_PARAMETER; @@ -342,7 +346,43 @@ 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. + // + 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)) { @@ -357,7 +397,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(); @@ -374,9 +418,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. // @@ -442,13 +490,14 @@ 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 { @@ -461,7 +510,6 @@ EfiHttpRequest ( } } - // // Save the RemotePort and RemoteHost. // @@ -480,6 +528,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); } @@ -498,13 +556,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. // @@ -538,10 +601,12 @@ EfiHttpRequest ( Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize); - if (EFI_ERROR (Status)) { + if (EFI_ERROR (Status) || NULL == RequestMsg) { goto Error3; } + ASSERT (RequestMsg != NULL); + // // 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 @@ -577,13 +642,13 @@ EfiHttpRequest ( return EFI_SUCCESS; Error5: - // - // We would have inserted a TxToken only if Request structure is not NULL. - // Hence check before we do a remove in this error case. - // - if (Request != NULL) { - NetMapRemoveTail (&HttpInstance->TxTokens, NULL); - } + // + // We would have inserted a TxToken only if Request structure is not NULL. + // Hence check before we do a remove in this error case. + // + if (Request != NULL) { + NetMapRemoveTail (&HttpInstance->TxTokens, NULL); + } Error4: if (RequestMsg != NULL) { @@ -591,9 +656,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); @@ -605,7 +675,6 @@ Error2: } Error1: - if (HostName != NULL) { FreePool (HostName); } @@ -639,7 +708,6 @@ HttpCancelTokens ( IN VOID *Context ) { - EFI_HTTP_TOKEN *Token; HTTP_TOKEN_WRAP *Wrap; HTTP_PROTOCOL *HttpInstance; @@ -657,42 +725,33 @@ HttpCancelTokens ( Wrap = (HTTP_TOKEN_WRAP *) Item->Value; ASSERT (Wrap != NULL); HttpInstance = Wrap->HttpInstance; - - // - // Free resources. - // - NetMapRemoveItem (Map, Item, NULL); if (!HttpInstance->LocalAddressIsIPv6) { - if (Wrap->TcpWrap.Tx4Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event); - } - if (Wrap->TcpWrap.Rx4Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Rx4Token.CompletionToken.Event); - } - - if (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Wrap->TcpWrap.Rx4Token.Packet.RxData->FragmentTable[0].FragmentBuffer); - } + // + // Cancle the Token before close its Event. + // + HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &Wrap->TcpWrap.Rx4Token.CompletionToken); - } else { - if (Wrap->TcpWrap.Tx6Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Tx6Token.CompletionToken.Event); + // + // Dispatch the DPC queued by the NotifyFunction of the canceled token's events. + // + DispatchDpc (); } - + } else { if (Wrap->TcpWrap.Rx6Token.CompletionToken.Event != NULL) { - gBS->CloseEvent (Wrap->TcpWrap.Rx6Token.CompletionToken.Event); - } + // + // Cancle the Token before close its Event. + // + HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &Wrap->TcpWrap.Rx6Token.CompletionToken); - if (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) { - FreePool (Wrap->TcpWrap.Rx6Token.Packet.RxData->FragmentTable[0].FragmentBuffer); + // + // Dispatch the DPC queued by the NotifyFunction of the canceled token's events. + // + DispatchDpc (); } } - - FreePool (Wrap); - // // If only one item is to be cancel, return EFI_ABORTED to stop // iterating the map any more. @@ -740,22 +799,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; } @@ -891,6 +958,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; @@ -907,16 +975,11 @@ HttpResponseWorker ( SizeofHeaders = 0; 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. // @@ -1007,6 +1070,7 @@ HttpResponseWorker ( // StatusCodeStr = HttpHeaders + AsciiStrLen (HTTP_VERSION_STR) + 1; if (StatusCodeStr == NULL) { + Status = EFI_NOT_READY; goto Error; } @@ -1017,6 +1081,7 @@ HttpResponseWorker ( // Tmp = AsciiStrStr (HttpHeaders, HTTP_CRLF_STR); if (Tmp == NULL) { + Status = EFI_NOT_READY; goto Error; } @@ -1063,7 +1128,8 @@ HttpResponseWorker ( if (SizeofHeaders != 0) { HeaderTmp = AllocateZeroPool (SizeofHeaders); if (HeaderTmp == NULL) { - goto Error; + Status = EFI_OUT_OF_RESOURCES; + goto Error2; } CopyMem (HeaderTmp, Tmp, SizeofHeaders); @@ -1075,7 +1141,7 @@ HttpResponseWorker ( // if (mHttpUtilities == NULL) { Status = EFI_NOT_READY; - goto Error; + goto Error2; } // @@ -1089,7 +1155,7 @@ HttpResponseWorker ( &HttpMsg->HeaderCount ); if (EFI_ERROR (Status)) { - goto Error; + goto Error2; } FreePool (HttpHeaders); @@ -1202,39 +1268,119 @@ HttpResponseWorker ( ASSERT (HttpInstance->MsgParser != NULL); - if (HttpInstance->TimeoutEvent == NULL) { + // + // We still need receive more data when there is no cache data and MsgParser is not NULL; + // + 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; + } + } + // - // Create TimeoutEvent for response + // Start the timer, and wait Timeout seconds to receive the body packet. // - Status = gBS->CreateEvent ( - EVT_TIMER, - TPL_CALLBACK, - NULL, - NULL, - &HttpInstance->TimeoutEvent - ); + Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND); if (EFI_ERROR (Status)) { - goto Error; + goto Error2; } - } + + Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance->TimeoutEvent); - // - // 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 Error; - } + gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0); + + if (EFI_ERROR (Status)) { + goto Error2; + } - // - // We still need receive more data when there is no cache data and MsgParser is not NULL; - // - Status = HttpTcpReceiveBody (Wrap, HttpMsg, HttpInstance->TimeoutEvent); + // + // Check whether we receive a complete HTTP message. + // + Status = HttpParseMessageBody ( + HttpInstance->MsgParser, + (UINTN) Fragment.Len, + (CHAR8 *) Fragment.Bulk + ); + if (EFI_ERROR (Status)) { + goto Error2; + } - gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0); + if (HttpIsMessageComplete (HttpInstance->MsgParser)) { + // + // Free the MsgParse since we already have a full HTTP message. + // + HttpFreeMsgParser (HttpInstance->MsgParser); + HttpInstance->MsgParser = NULL; + } - if (EFI_ERROR (Status)) { - goto Error; + // + // 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; @@ -1257,17 +1403,35 @@ Exit: return Status; Error2: - NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem); + if (ValueInItem != NULL) { + NetMapInsertHead (&HttpInstance->TxTokens, ValueInItem->HttpToken, ValueInItem); + } Error: - HttpTcpTokenCleanup (Wrap); + Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap->HttpToken); + if (Item != NULL) { + NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL); + } + + 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) { @@ -1378,9 +1542,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);