12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904 |
- /** @file
- The implementation for the 'http' Shell command.
- Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>
- Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved. <BR>
- (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
- Copyright (c) 2020, Broadcom. All rights reserved. <BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "Http.h"
- #define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32
- //
- // Constant strings and definitions related to the message
- // indicating the amount of progress in the dowloading of a HTTP file.
- //
- //
- // Number of steps in the progression slider.
- //
- #define HTTP_PROGRESS_SLIDER_STEPS \
- ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 3)
- //
- // Size in number of characters plus one (final zero) of the message to
- // indicate the progress of an HTTP download. The format is "[(progress slider:
- // 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There
- // are thus the number of characters in HTTP_PROGR_FRAME[] plus 11 characters
- // (2 // spaces, "Kb" and seven characters for the number of KBytes).
- //
- #define HTTP_PROGRESS_MESSAGE_SIZE \
- ((sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) + 12)
- //
- // Buffer size. Note that larger buffer does not mean better speed.
- //
- #define DEFAULT_BUF_SIZE SIZE_32KB
- #define MAX_BUF_SIZE SIZE_4MB
- #define MIN_PARAM_COUNT 2
- #define MAX_PARAM_COUNT 4
- #define NEED_REDIRECTION(Code) \
- (((Code >= HTTP_STATUS_300_MULTIPLE_CHOICES) \
- && (Code <= HTTP_STATUS_307_TEMPORARY_REDIRECT)) \
- || (Code == HTTP_STATUS_308_PERMANENT_REDIRECT))
- #define CLOSE_HTTP_HANDLE(ControllerHandle, HttpChildHandle) \
- do { \
- if (HttpChildHandle) { \
- CloseProtocolAndDestroyServiceChild ( \
- ControllerHandle, \
- &gEfiHttpServiceBindingProtocolGuid, \
- &gEfiHttpProtocolGuid, \
- HttpChildHandle \
- ); \
- HttpChildHandle = NULL; \
- } \
- } while (0)
- typedef enum {
- HdrHost,
- HdrConn,
- HdrAgent,
- HdrMax
- } HDR_TYPE;
- #define USER_AGENT_HDR "Mozilla/5.0 (EDK2; Linux) Gecko/20100101 Firefox/79.0"
- #define TIMER_MAX_TIMEOUT_S 10
- //
- // File name to use when Uri ends with "/".
- //
- #define DEFAULT_HTML_FILE L"index.html"
- #define DEFAULT_HTTP_PROTO L"http"
- //
- // String to delete the HTTP progress message to be able to update it :
- // (HTTP_PROGRESS_MESSAGE_SIZE-1) '\b'.
- //
- #define HTTP_PROGRESS_DEL \
- L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\
- \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
- #define HTTP_KB L"\b\b\b\b\b\b\b\b\b\b"
- //
- // Frame for the progression slider.
- //
- #define HTTP_PROGR_FRAME L"[ ]"
- //
- // Improve readability by using these macros.
- //
- #define PRINT_HII(token, ...) \
- ShellPrintHiiEx (\
- -1, -1, NULL, token, mHttpHiiHandle, __VA_ARGS__)
- #define PRINT_HII_APP(token, value) \
- PRINT_HII (token, HTTP_APP_NAME, value)
- //
- // TimeBaseLib.h constants.
- // These will be removed once the library gets fixed.
- //
- //
- // Define EPOCH (1970-JANUARY-01) in the Julian Date representation.
- //
- #define EPOCH_JULIAN_DATE 2440588
- //
- // Seconds per unit.
- //
- #define SEC_PER_MIN ((UINTN) 60)
- #define SEC_PER_HOUR ((UINTN) 3600)
- #define SEC_PER_DAY ((UINTN) 86400)
- //
- // String descriptions for server errors.
- //
- STATIC CONST CHAR16 *ErrStatusDesc[] =
- {
- L"400 Bad Request",
- L"401 Unauthorized",
- L"402 Payment required",
- L"403 Forbidden",
- L"404 Not Found",
- L"405 Method not allowed",
- L"406 Not acceptable",
- L"407 Proxy authentication required",
- L"408 Request time out",
- L"409 Conflict",
- L"410 Gone",
- L"411 Length required",
- L"412 Precondition failed",
- L"413 Request entity too large",
- L"414 Request URI to large",
- L"415 Unsupported media type",
- L"416 Requested range not satisfied",
- L"417 Expectation failed",
- L"500 Internal server error",
- L"501 Not implemented",
- L"502 Bad gateway",
- L"503 Service unavailable",
- L"504 Gateway timeout",
- L"505 HTTP version not supported"
- };
- STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
- { L"-i", TypeValue },
- { L"-k", TypeFlag },
- { L"-l", TypeValue },
- { L"-m", TypeFlag },
- { L"-s", TypeValue },
- { L"-t", TypeValue },
- { NULL, TypeMax }
- };
- //
- // Local File Handle.
- //
- STATIC SHELL_FILE_HANDLE mFileHandle = NULL;
- //
- // Path of the local file, Unicode encoded.
- //
- STATIC CONST CHAR16 *mLocalFilePath;
- STATIC BOOLEAN gRequestCallbackComplete = FALSE;
- STATIC BOOLEAN gResponseCallbackComplete = FALSE;
- STATIC BOOLEAN gHttpError;
- EFI_HII_HANDLE mHttpHiiHandle;
- //
- // Functions declarations.
- //
- /**
- Check and convert the UINT16 option values of the 'http' command.
- @param[in] ValueStr Value as an Unicode encoded string.
- @param[out] Value UINT16 value.
- @retval TRUE The value was returned.
- @retval FALSE A parsing error occured.
- **/
- STATIC
- BOOLEAN
- StringToUint16 (
- IN CONST CHAR16 *ValueStr,
- OUT UINT16 *Value
- );
- /**
- Get the name of the NIC.
- @param[in] ControllerHandle The network physical device handle.
- @param[in] NicNumber The network physical device number.
- @param[out] NicName Address where to store the NIC name.
- The memory area has to be at least
- IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
- double byte wide.
- @retval EFI_SUCCESS The name of the NIC was returned.
- @retval Others The creation of the child for the Managed
- Network Service failed or the opening of
- the Managed Network Protocol failed or
- the operational parameters for the
- Managed Network Protocol could not be
- read.
- **/
- STATIC
- EFI_STATUS
- GetNicName (
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NicNumber,
- OUT CHAR16 *NicName
- );
- /**
- Create a child for the service identified by its service binding protocol GUID
- and get from the child the interface of the protocol identified by its GUID.
- @param[in] ControllerHandle Controller handle.
- @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
- service to be created.
- @param[in] ProtocolGuid GUID of the protocol to be open.
- @param[out] ChildHandle Address where the handler of the
- created child is returned. NULL is
- returned in case of error.
- @param[out] Interface Address where a pointer to the
- protocol interface is returned in
- case of success.
- @retval EFI_SUCCESS The child was created and the protocol opened.
- @retval Others Either the creation of the child or the opening
- of the protocol failed.
- **/
- STATIC
- EFI_STATUS
- CreateServiceChildAndOpenProtocol (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_GUID *ServiceBindingProtocolGuid,
- IN EFI_GUID *ProtocolGuid,
- OUT EFI_HANDLE *ChildHandle,
- OUT VOID **Interface
- );
- /**
- Close the protocol identified by its GUID on the child handle of the service
- identified by its service binding protocol GUID, then destroy the child
- handle.
- @param[in] ControllerHandle Controller handle.
- @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
- service to be destroyed.
- @param[in] ProtocolGuid GUID of the protocol to be closed.
- @param[in] ChildHandle Handle of the child to be destroyed.
- **/
- STATIC
- VOID
- CloseProtocolAndDestroyServiceChild (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_GUID *ServiceBindingProtocolGuid,
- IN EFI_GUID *ProtocolGuid,
- IN EFI_HANDLE ChildHandle
- );
- /**
- Worker function that download the data of a file from an HTTP server given
- the path of the file and its size.
- @param[in] Context A pointer to the download context.
- @retval EFI_SUCCESS The file was downloaded.
- @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
- @retval Others The downloading of the file
- from the server failed.
- **/
- STATIC
- EFI_STATUS
- DownloadFile (
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN EFI_HANDLE ControllerHandle,
- IN CHAR16 *NicName
- );
- /**
- Cleans off leading and trailing spaces and tabs.
- @param[in] String pointer to the string to trim them off.
- @retval EFI_SUCCESS No errors.
- @retval EFI_INVALID_PARAMETER String pointer is NULL.
- **/
- STATIC
- EFI_STATUS
- TrimSpaces (
- IN CHAR16 *String
- )
- {
- CHAR16 *Str;
- UINTN Len;
- ASSERT (String != NULL);
- if (String == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- Str = String;
- //
- // Remove any whitespace at the beginning of the Str.
- //
- while (*Str == L' ' || *Str == L'\t') {
- Str++;
- }
- //
- // Remove any whitespace at the end of the Str.
- //
- do {
- Len = StrLen (Str);
- if (!Len || ((Str[Len - 1] != L' ') && (Str[Len - 1] != '\t'))) {
- break;
- }
- Str[Len - 1] = CHAR_NULL;
- } while (Len);
- CopyMem (String, Str, StrSize (Str));
- return EFI_SUCCESS;
- }
- //
- // Callbacks for request and response.
- // We just acknowledge that operation has completed here.
- //
- /**
- Callback to set the request completion flag.
- @param[in] Event: The event.
- @param[in] Context: pointer to Notification Context.
- **/
- STATIC
- VOID
- EFIAPI
- RequestCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- gRequestCallbackComplete = TRUE;
- }
- /**
- Callback to set the response completion flag.
- @param[in] Event: The event.
- @param[in] Context: pointer to Notification Context.
- **/
- STATIC
- VOID
- EFIAPI
- ResponseCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
- {
- gResponseCallbackComplete = TRUE;
- }
- //
- // Set of functions from TimeBaseLib.
- // This will be removed once TimeBaseLib is enabled for ShellPkg.
- //
- /**
- Calculate Epoch days.
- @param[in] Time - a pointer to the EFI_TIME abstraction.
- @retval Number of days elapsed since EPOCH_JULIAN_DAY.
- **/
- STATIC
- UINTN
- EfiGetEpochDays (
- IN EFI_TIME *Time
- )
- {
- UINTN a;
- UINTN y;
- UINTN m;
- //
- // Absolute Julian Date representation of the supplied Time.
- //
- UINTN JulianDate;
- //
- // Number of days elapsed since EPOCH_JULIAN_DAY.
- //
- UINTN EpochDays;
- a = (14 - Time->Month) / 12;
- y = Time->Year + 4800 - a;
- m = Time->Month + (12 * a) - 3;
- JulianDate = Time->Day + ((153 * m + 2) / 5) + (365 * y) + (y / 4) -
- (y / 100) + (y / 400) - 32045;
- ASSERT (JulianDate >= EPOCH_JULIAN_DATE);
- EpochDays = JulianDate - EPOCH_JULIAN_DATE;
- return EpochDays;
- }
- /**
- Converts EFI_TIME to Epoch seconds
- (elapsed since 1970 JANUARY 01, 00:00:00 UTC).
- @param[in] Time: a pointer to EFI_TIME abstraction.
- **/
- STATIC
- UINTN
- EFIAPI
- EfiTimeToEpoch (
- IN EFI_TIME *Time
- )
- {
- //
- // Number of days elapsed since EPOCH_JULIAN_DAY.
- //
- UINTN EpochDays;
- UINTN EpochSeconds;
- EpochDays = EfiGetEpochDays (Time);
- EpochSeconds = (EpochDays * SEC_PER_DAY) +
- ((UINTN)Time->Hour * SEC_PER_HOUR) +
- (Time->Minute * SEC_PER_MIN) + Time->Second;
- return EpochSeconds;
- }
- /**
- Function for 'http' command.
- @param[in] ImageHandle Handle to the Image (NULL if Internal).
- @param[in] SystemTable Pointer to the System Table (NULL if Internal).
- @retval SHELL_SUCCESS The 'http' command completed successfully.
- @retval SHELL_ABORTED The Shell Library initialization failed.
- @retval SHELL_INVALID_PARAMETER At least one of the command's arguments is
- not valid.
- @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.
- @retval SHELL_NOT_FOUND Network Interface Card not found.
- @retval SHELL_UNSUPPORTED Command was valid, but the server returned
- a status code indicating some error.
- Examine the file requested for error body.
- **/
- SHELL_STATUS
- RunHttp (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
- {
- EFI_STATUS Status;
- LIST_ENTRY *CheckPackage;
- UINTN ParamCount;
- UINTN HandleCount;
- UINTN NicNumber;
- UINTN InitialSize;
- UINTN ParamOffset;
- UINTN StartSize;
- CHAR16 *ProblemParam;
- CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH];
- CHAR16 *Walker1;
- CHAR16 *VStr;
- CONST CHAR16 *UserNicName;
- CONST CHAR16 *ValueStr;
- CONST CHAR16 *RemoteFilePath;
- CONST CHAR16 *Walker;
- EFI_HTTPv4_ACCESS_POINT IPv4Node;
- EFI_HANDLE *Handles;
- EFI_HANDLE ControllerHandle;
- HTTP_DOWNLOAD_CONTEXT Context;
- BOOLEAN NicFound;
- ProblemParam = NULL;
- RemoteFilePath = NULL;
- NicFound = FALSE;
- Handles = NULL;
- //
- // Initialize the Shell library (we must be in non-auto-init...).
- //
- ParamOffset = 0;
- gHttpError = FALSE;
- Status = ShellInitialize ();
- if (EFI_ERROR (Status)) {
- ASSERT_EFI_ERROR (Status);
- return SHELL_ABORTED;
- }
- ZeroMem (&Context, sizeof (Context));
- //
- // Parse the command line.
- //
- Status = ShellCommandLineParse (
- ParamList,
- &CheckPackage,
- &ProblemParam,
- TRUE
- );
- if (EFI_ERROR (Status)) {
- if ( (Status == EFI_VOLUME_CORRUPTED)
- && (ProblemParam != NULL))
- {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_PROBLEM), ProblemParam);
- SHELL_FREE_NON_NULL (ProblemParam);
- } else {
- ASSERT (FALSE);
- }
- goto Error;
- }
- //
- // Check the number of parameters.
- //
- Status = EFI_INVALID_PARAMETER;
- ParamCount = ShellCommandLineGetCount (CheckPackage);
- if (ParamCount > MAX_PARAM_COUNT) {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_MANY), NULL);
- goto Error;
- }
- if (ParamCount < MIN_PARAM_COUNT) {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_TOO_FEW), NULL);
- goto Error;
- }
- ZeroMem (&Context.HttpConfigData, sizeof (Context.HttpConfigData));
- ZeroMem (&IPv4Node, sizeof (IPv4Node));
- IPv4Node.UseDefaultAddress = TRUE;
- Context.HttpConfigData.HttpVersion = HttpVersion11;
- Context.HttpConfigData.AccessPoint.IPv4Node = &IPv4Node;
- //
- // Get the host address (not necessarily IPv4 format).
- //
- ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1);
- if (!ValueStr) {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr);
- goto Error;
- } else {
- StartSize = 0;
- TrimSpaces ((CHAR16 *)ValueStr);
- if (!StrStr (ValueStr, L"://")) {
- Context.ServerAddrAndProto = StrnCatGrow (
- &Context.ServerAddrAndProto,
- &StartSize,
- DEFAULT_HTTP_PROTO,
- StrLen (DEFAULT_HTTP_PROTO)
- );
- Context.ServerAddrAndProto = StrnCatGrow (
- &Context.ServerAddrAndProto,
- &StartSize,
- L"://",
- StrLen (L"://")
- );
- VStr = (CHAR16 *)ValueStr;
- } else {
- VStr = StrStr (ValueStr, L"://") + StrLen (L"://");
- }
- for (Walker1 = VStr; *Walker1; Walker1++) {
- if (*Walker1 == L'/') {
- break;
- }
- }
- if (*Walker1 == L'/') {
- ParamOffset = 1;
- RemoteFilePath = Walker1;
- }
- Context.ServerAddrAndProto = StrnCatGrow (
- &Context.ServerAddrAndProto,
- &StartSize,
- ValueStr,
- StrLen (ValueStr) - StrLen (Walker1)
- );
- if (!Context.ServerAddrAndProto) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- }
- if (!RemoteFilePath) {
- RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2);
- if (!RemoteFilePath) {
- //
- // If no path given, assume just "/".
- //
- RemoteFilePath = L"/";
- }
- }
- TrimSpaces ((CHAR16 *)RemoteFilePath);
- if (ParamCount == MAX_PARAM_COUNT - ParamOffset) {
- mLocalFilePath = ShellCommandLineGetRawValue (
- CheckPackage,
- MAX_PARAM_COUNT - 1 - ParamOffset
- );
- } else {
- Walker = RemoteFilePath + StrLen (RemoteFilePath);
- while ((--Walker) >= RemoteFilePath) {
- if ((*Walker == L'\\') ||
- (*Walker == L'/'))
- {
- break;
- }
- }
- mLocalFilePath = Walker + 1;
- }
- if (!StrLen (mLocalFilePath)) {
- mLocalFilePath = DEFAULT_HTML_FILE;
- }
- InitialSize = 0;
- Context.Uri = StrnCatGrow (
- &Context.Uri,
- &InitialSize,
- RemoteFilePath,
- StrLen (RemoteFilePath)
- );
- if (!Context.Uri) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- //
- // Get the name of the Network Interface Card to be used if any.
- //
- UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i");
- ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l");
- if ( (ValueStr != NULL)
- && (!StringToUint16 (
- ValueStr,
- &Context.HttpConfigData.AccessPoint.IPv4Node->LocalPort
- )
- ))
- {
- goto Error;
- }
- Context.BufferSize = DEFAULT_BUF_SIZE;
- ValueStr = ShellCommandLineGetValue (CheckPackage, L"-s");
- if (ValueStr != NULL) {
- Context.BufferSize = ShellStrToUintn (ValueStr);
- if (!Context.BufferSize || (Context.BufferSize > MAX_BUF_SIZE)) {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr);
- goto Error;
- }
- }
- ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t");
- if (ValueStr != NULL) {
- Context.HttpConfigData.TimeOutMillisec = (UINT32)ShellStrToUintn (ValueStr);
- }
- //
- // Locate all HTTP Service Binding protocols.
- //
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiManagedNetworkServiceBindingProtocolGuid,
- NULL,
- &HandleCount,
- &Handles
- );
- if (EFI_ERROR (Status) || (HandleCount == 0)) {
- PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NO_NIC), NULL);
- if (!EFI_ERROR (Status)) {
- Status = EFI_NOT_FOUND;
- }
- goto Error;
- }
- Status = EFI_NOT_FOUND;
- Context.Flags = 0;
- if (ShellCommandLineGetFlag (CheckPackage, L"-m")) {
- Context.Flags |= DL_FLAG_TIME;
- }
- if (ShellCommandLineGetFlag (CheckPackage, L"-k")) {
- Context.Flags |= DL_FLAG_KEEP_BAD;
- }
- for (NicNumber = 0;
- (NicNumber < HandleCount) && (Status != EFI_SUCCESS);
- NicNumber++)
- {
- ControllerHandle = Handles[NicNumber];
- Status = GetNicName (ControllerHandle, NicNumber, NicName);
- if (EFI_ERROR (Status)) {
- PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NAME), NicNumber, Status);
- continue;
- }
- if (UserNicName != NULL) {
- if (StrCmp (NicName, UserNicName) != 0) {
- Status = EFI_NOT_FOUND;
- continue;
- }
- NicFound = TRUE;
- }
- Status = DownloadFile (&Context, ControllerHandle, NicName);
- PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL);
- if (EFI_ERROR (Status)) {
- PRINT_HII (
- STRING_TOKEN (STR_HTTP_ERR_DOWNLOAD),
- RemoteFilePath,
- NicName,
- Status
- );
- //
- // If a user aborted the operation,
- // do not try another controller.
- //
- if (Status == EFI_ABORTED) {
- goto Error;
- }
- }
- if (gHttpError) {
- //
- // This is not related to connection, so no need to repeat with
- // another interface.
- //
- break;
- }
- }
- if ((UserNicName != NULL) && (!NicFound)) {
- PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_NIC_NOT_FOUND), UserNicName);
- }
- Error:
- ShellCommandLineFreeVarList (CheckPackage);
- SHELL_FREE_NON_NULL (Handles);
- SHELL_FREE_NON_NULL (Context.ServerAddrAndProto);
- SHELL_FREE_NON_NULL (Context.Uri);
- return Status & ~MAX_BIT;
- }
- /**
- Check and convert the UINT16 option values of the 'http' command
- @param[in] ValueStr Value as an Unicode encoded string
- @param[out] Value UINT16 value
- @retval TRUE The value was returned.
- @retval FALSE A parsing error occured.
- **/
- STATIC
- BOOLEAN
- StringToUint16 (
- IN CONST CHAR16 *ValueStr,
- OUT UINT16 *Value
- )
- {
- UINTN Val;
- Val = ShellStrToUintn (ValueStr);
- if (Val > MAX_UINT16) {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_PARAM_INV), ValueStr);
- return FALSE;
- }
- *Value = (UINT16)Val;
- return TRUE;
- }
- /**
- Get the name of the NIC.
- @param[in] ControllerHandle The network physical device handle.
- @param[in] NicNumber The network physical device number.
- @param[out] NicName Address where to store the NIC name.
- The memory area has to be at least
- IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH
- double byte wide.
- @retval EFI_SUCCESS The name of the NIC was returned.
- @retval Others The creation of the child for the Managed
- Network Service failed or the opening of
- the Managed Network Protocol failed or
- the operational parameters for the
- Managed Network Protocol could not be
- read.
- **/
- STATIC
- EFI_STATUS
- GetNicName (
- IN EFI_HANDLE ControllerHandle,
- IN UINTN NicNumber,
- OUT CHAR16 *NicName
- )
- {
- EFI_STATUS Status;
- EFI_HANDLE MnpHandle;
- EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
- EFI_SIMPLE_NETWORK_MODE SnpMode;
- Status = CreateServiceChildAndOpenProtocol (
- ControllerHandle,
- &gEfiManagedNetworkServiceBindingProtocolGuid,
- &gEfiManagedNetworkProtocolGuid,
- &MnpHandle,
- (VOID **)&Mnp
- );
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);
- if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {
- goto Error;
- }
- UnicodeSPrint (
- NicName,
- IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH,
- SnpMode.IfType == NET_IFTYPE_ETHERNET ? L"eth%d" : L"unk%d",
- NicNumber
- );
- Status = EFI_SUCCESS;
- Error:
- if (MnpHandle != NULL) {
- CloseProtocolAndDestroyServiceChild (
- ControllerHandle,
- &gEfiManagedNetworkServiceBindingProtocolGuid,
- &gEfiManagedNetworkProtocolGuid,
- MnpHandle
- );
- }
- return Status;
- }
- /**
- Create a child for the service identified by its service binding protocol GUID
- and get from the child the interface of the protocol identified by its GUID.
- @param[in] ControllerHandle Controller handle.
- @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
- service to be created.
- @param[in] ProtocolGuid GUID of the protocol to be open.
- @param[out] ChildHandle Address where the handler of the
- created child is returned. NULL is
- returned in case of error.
- @param[out] Interface Address where a pointer to the
- protocol interface is returned in
- case of success.
- @retval EFI_SUCCESS The child was created and the protocol opened.
- @retval Others Either the creation of the child or the opening
- of the protocol failed.
- **/
- STATIC
- EFI_STATUS
- CreateServiceChildAndOpenProtocol (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_GUID *ServiceBindingProtocolGuid,
- IN EFI_GUID *ProtocolGuid,
- OUT EFI_HANDLE *ChildHandle,
- OUT VOID **Interface
- )
- {
- EFI_STATUS Status;
- *ChildHandle = NULL;
- Status = NetLibCreateServiceChild (
- ControllerHandle,
- gImageHandle,
- ServiceBindingProtocolGuid,
- ChildHandle
- );
- if (!EFI_ERROR (Status)) {
- Status = gBS->OpenProtocol (
- *ChildHandle,
- ProtocolGuid,
- Interface,
- gImageHandle,
- ControllerHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- if (EFI_ERROR (Status)) {
- NetLibDestroyServiceChild (
- ControllerHandle,
- gImageHandle,
- ServiceBindingProtocolGuid,
- *ChildHandle
- );
- *ChildHandle = NULL;
- }
- }
- return Status;
- }
- /**
- Close the protocol identified by its GUID on the child handle of the service
- identified by its service binding protocol GUID, then destroy the child
- handle.
- @param[in] ControllerHandle Controller handle.
- @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the
- service to be destroyed.
- @param[in] ProtocolGuid GUID of the protocol to be closed.
- @param[in] ChildHandle Handle of the child to be destroyed.
- **/
- STATIC
- VOID
- CloseProtocolAndDestroyServiceChild (
- IN EFI_HANDLE ControllerHandle,
- IN EFI_GUID *ServiceBindingProtocolGuid,
- IN EFI_GUID *ProtocolGuid,
- IN EFI_HANDLE ChildHandle
- )
- {
- gBS->CloseProtocol (
- ChildHandle,
- ProtocolGuid,
- gImageHandle,
- ControllerHandle
- );
- NetLibDestroyServiceChild (
- ControllerHandle,
- gImageHandle,
- ServiceBindingProtocolGuid,
- ChildHandle
- );
- }
- /**
- Wait until operation completes. Completion is indicated by
- setting of an appropriate variable.
- @param[in] Context A pointer to the HTTP download context.
- @param[in, out] CallBackComplete A pointer to the callback completion
- variable set by the callback.
- @retval EFI_SUCCESS Callback signalled completion.
- @retval EFI_TIMEOUT Timed out waiting for completion.
- @retval Others Error waiting for completion.
- **/
- STATIC
- EFI_STATUS
- WaitForCompletion (
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN OUT BOOLEAN *CallBackComplete
- )
- {
- EFI_STATUS Status;
- EFI_EVENT WaitEvt;
- Status = EFI_SUCCESS;
- //
- // Use a timer to measure timeout. Cannot use Stall here!
- //
- Status = gBS->CreateEvent (
- EVT_TIMER,
- TPL_CALLBACK,
- NULL,
- NULL,
- &WaitEvt
- );
- ASSERT_EFI_ERROR (Status);
- if (!EFI_ERROR (Status)) {
- Status = gBS->SetTimer (
- WaitEvt,
- TimerRelative,
- EFI_TIMER_PERIOD_SECONDS (TIMER_MAX_TIMEOUT_S)
- );
- ASSERT_EFI_ERROR (Status);
- }
- while ( !*CallBackComplete
- && (!EFI_ERROR (Status))
- && EFI_ERROR (gBS->CheckEvent (WaitEvt)))
- {
- Status = Context->Http->Poll (Context->Http);
- if ( !Context->ContentDownloaded
- && (CallBackComplete == &gResponseCallbackComplete))
- {
- //
- // An HTTP server may just send a response redirection header.
- // In this case, don't wait for the event as
- // it might never happen and we waste 10s waiting.
- // Note that at this point Response may not has been populated,
- // so it needs to be checked first.
- //
- if ( Context->ResponseToken.Message
- && Context->ResponseToken.Message->Data.Response
- && (NEED_REDIRECTION (
- Context->ResponseToken.Message->Data.Response->StatusCode
- )
- ))
- {
- break;
- }
- }
- }
- gBS->SetTimer (WaitEvt, TimerCancel, 0);
- gBS->CloseEvent (WaitEvt);
- if (*CallBackComplete) {
- return EFI_SUCCESS;
- }
- if (!EFI_ERROR (Status)) {
- Status = EFI_TIMEOUT;
- }
- return Status;
- }
- /**
- Generate and send a request to the http server.
- @param[in] Context HTTP download context.
- @param[in] DownloadUrl Fully qualified URL to be downloaded.
- @retval EFI_SUCCESS Request has been sent successfully.
- @retval EFI_INVALID_PARAMETER Invalid URL.
- @retval EFI_OUT_OF_RESOURCES Out of memory.
- @retval EFI_DEVICE_ERROR If HTTPS is used, this probably
- means that TLS support either was not
- installed or not configured.
- @retval Others Error sending the request.
- **/
- STATIC
- EFI_STATUS
- SendRequest (
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN CHAR16 *DownloadUrl
- )
- {
- EFI_HTTP_REQUEST_DATA RequestData;
- EFI_HTTP_HEADER RequestHeader[HdrMax];
- EFI_HTTP_MESSAGE RequestMessage;
- EFI_STATUS Status;
- CHAR16 *Host;
- UINTN StringSize;
- ZeroMem (&RequestData, sizeof (RequestData));
- ZeroMem (&RequestHeader, sizeof (RequestHeader));
- ZeroMem (&RequestMessage, sizeof (RequestMessage));
- ZeroMem (&Context->RequestToken, sizeof (Context->RequestToken));
- RequestHeader[HdrHost].FieldName = "Host";
- RequestHeader[HdrConn].FieldName = "Connection";
- RequestHeader[HdrAgent].FieldName = "User-Agent";
- Host = (CHAR16 *)Context->ServerAddrAndProto;
- while (*Host != CHAR_NULL && *Host != L'/') {
- Host++;
- }
- if (*Host == CHAR_NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Get the next slash.
- //
- Host++;
- //
- // And now the host name.
- //
- Host++;
- StringSize = StrLen (Host) + 1;
- RequestHeader[HdrHost].FieldValue = AllocatePool (StringSize);
- if (!RequestHeader[HdrHost].FieldValue) {
- return EFI_OUT_OF_RESOURCES;
- }
- UnicodeStrToAsciiStrS (
- Host,
- RequestHeader[HdrHost].FieldValue,
- StringSize
- );
- RequestHeader[HdrConn].FieldValue = "close";
- RequestHeader[HdrAgent].FieldValue = USER_AGENT_HDR;
- RequestMessage.HeaderCount = HdrMax;
- RequestData.Method = HttpMethodGet;
- RequestData.Url = DownloadUrl;
- RequestMessage.Data.Request = &RequestData;
- RequestMessage.Headers = RequestHeader;
- RequestMessage.BodyLength = 0;
- RequestMessage.Body = NULL;
- Context->RequestToken.Event = NULL;
- //
- // Completion callback event to be set when Request completes.
- //
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- RequestCallback,
- Context,
- &Context->RequestToken.Event
- );
- ASSERT_EFI_ERROR (Status);
- Context->RequestToken.Status = EFI_SUCCESS;
- Context->RequestToken.Message = &RequestMessage;
- gRequestCallbackComplete = FALSE;
- Status = Context->Http->Request (Context->Http, &Context->RequestToken);
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- Status = WaitForCompletion (Context, &gRequestCallbackComplete);
- if (EFI_ERROR (Status)) {
- Context->Http->Cancel (Context->Http, &Context->RequestToken);
- }
- Error:
- SHELL_FREE_NON_NULL (RequestHeader[HdrHost].FieldValue);
- if (Context->RequestToken.Event) {
- gBS->CloseEvent (Context->RequestToken.Event);
- ZeroMem (&Context->RequestToken, sizeof (Context->RequestToken));
- }
- return Status;
- }
- /**
- Update the progress of a file download
- This procedure is called each time a new HTTP body portion is received.
- @param[in] Context HTTP download context.
- @param[in] DownloadLen Portion size, in bytes.
- @param[in] Buffer The pointer to the parsed buffer.
- @retval EFI_SUCCESS Portion saved.
- @retval Other Error saving the portion.
- **/
- STATIC
- EFI_STATUS
- EFIAPI
- SavePortion (
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN UINTN DownloadLen,
- IN CHAR8 *Buffer
- )
- {
- CHAR16 Progress[HTTP_PROGRESS_MESSAGE_SIZE];
- UINTN NbOfKb;
- UINTN Index;
- UINTN LastStep;
- UINTN Step;
- EFI_STATUS Status;
- LastStep = 0;
- Step = 0;
- ShellSetFilePosition (mFileHandle, Context->LastReportedNbOfBytes);
- Status = ShellWriteFile (mFileHandle, &DownloadLen, Buffer);
- if (EFI_ERROR (Status)) {
- if (Context->ContentDownloaded > 0) {
- PRINT_HII (STRING_TOKEN (STR_GEN_CRLF), NULL);
- }
- PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_WRITE), mLocalFilePath, Status);
- return Status;
- }
- if (Context->ContentDownloaded == 0) {
- ShellPrintEx (-1, -1, L"%s 0 Kb", HTTP_PROGR_FRAME);
- }
- Context->ContentDownloaded += DownloadLen;
- NbOfKb = Context->ContentDownloaded >> 10;
- Progress[0] = L'\0';
- if (Context->ContentLength) {
- LastStep = (Context->LastReportedNbOfBytes * HTTP_PROGRESS_SLIDER_STEPS) /
- Context->ContentLength;
- Step = (Context->ContentDownloaded * HTTP_PROGRESS_SLIDER_STEPS) /
- Context->ContentLength;
- }
- Context->LastReportedNbOfBytes = Context->ContentDownloaded;
- if (Step <= LastStep) {
- if (!Context->ContentLength) {
- //
- // Update downloaded size, there is no length info available.
- //
- ShellPrintEx (-1, -1, L"%s", HTTP_KB);
- ShellPrintEx (-1, -1, L"%7d Kb", NbOfKb);
- }
- return EFI_SUCCESS;
- }
- ShellPrintEx (-1, -1, L"%s", HTTP_PROGRESS_DEL);
- Status = StrCpyS (Progress, HTTP_PROGRESS_MESSAGE_SIZE, HTTP_PROGR_FRAME);
- if (EFI_ERROR (Status)) {
- return Status;
- }
- for (Index = 1; Index < Step; Index++) {
- Progress[Index] = L'=';
- }
- if (Step) {
- Progress[Step] = L'>';
- }
- UnicodeSPrint (
- Progress + (sizeof (HTTP_PROGR_FRAME) / sizeof (CHAR16)) - 1,
- sizeof (Progress) - sizeof (HTTP_PROGR_FRAME),
- L" %7d Kb",
- NbOfKb
- );
- ShellPrintEx (-1, -1, L"%s", Progress);
- return EFI_SUCCESS;
- }
- /**
- Replace the original Host and Uri with Host and Uri returned by the
- HTTP server in 'Location' header (redirection).
- @param[in] Location A pointer to the 'Location' string
- provided by HTTP server.
- @param[in] Context A pointer to HTTP download context.
- @param[in] DownloadUrl Fully qualified HTTP URL.
- @retval EFI_SUCCESS Host and Uri were successfully set.
- @retval EFI_OUT_OF_RESOURCES Error setting Host or Uri.
- **/
- STATIC
- EFI_STATUS
- SetHostURI (
- IN CHAR8 *Location,
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN CHAR16 *DownloadUrl
- )
- {
- EFI_STATUS Status;
- UINTN StringSize;
- UINTN FirstStep;
- UINTN Idx;
- UINTN Step;
- CHAR8 *Walker;
- CHAR16 *Temp;
- CHAR8 *Tmp;
- CHAR16 *Url;
- BOOLEAN IsAbEmptyUrl;
- Tmp = NULL;
- Url = NULL;
- IsAbEmptyUrl = FALSE;
- FirstStep = 0;
- StringSize = (AsciiStrSize (Location) * sizeof (CHAR16));
- Url = AllocateZeroPool (StringSize);
- if (!Url) {
- return EFI_OUT_OF_RESOURCES;
- }
- Status = AsciiStrToUnicodeStrS (
- (CONST CHAR8 *)Location,
- Url,
- StringSize
- );
- if (EFI_ERROR (Status)) {
- goto Error;
- }
- //
- // If an HTTP server redirects to the same location more than once,
- // then stop attempts and tell it is not reachable.
- //
- if (!StrCmp (Url, DownloadUrl)) {
- Status = EFI_NO_MAPPING;
- goto Error;
- }
- if (AsciiStrLen (Location) > 2) {
- //
- // Some servers return 'Location: //server/resource'
- //
- IsAbEmptyUrl = (Location[0] == '/') && (Location[1] == '/');
- if (IsAbEmptyUrl) {
- //
- // Skip first "//"
- //
- Location += 2;
- FirstStep = 1;
- }
- }
- if (AsciiStrStr (Location, "://") || IsAbEmptyUrl) {
- Idx = 0;
- Walker = Location;
- for (Step = FirstStep; Step < 2; Step++) {
- for ( ; *Walker != '/' && *Walker != '\0'; Walker++) {
- Idx++;
- }
- if (!Step) {
- //
- // Skip "//"
- //
- Idx += 2;
- Walker += 2;
- }
- }
- Tmp = AllocateZeroPool (Idx + 1);
- if (!Tmp) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- CopyMem (Tmp, Location, Idx);
- //
- // Location now points to Uri
- //
- Location += Idx;
- StringSize = (Idx + 1) * sizeof (CHAR16);
- SHELL_FREE_NON_NULL (Context->ServerAddrAndProto);
- Temp = AllocateZeroPool (StringSize);
- if (!Temp) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- Status = AsciiStrToUnicodeStrS (
- (CONST CHAR8 *)Tmp,
- Temp,
- StringSize
- );
- if (EFI_ERROR (Status)) {
- SHELL_FREE_NON_NULL (Temp);
- goto Error;
- }
- Idx = 0;
- if (IsAbEmptyUrl) {
- Context->ServerAddrAndProto = StrnCatGrow (
- &Context->ServerAddrAndProto,
- &Idx,
- L"http://",
- StrLen (L"http://")
- );
- }
- Context->ServerAddrAndProto = StrnCatGrow (
- &Context->ServerAddrAndProto,
- &Idx,
- Temp,
- StrLen (Temp)
- );
- SHELL_FREE_NON_NULL (Temp);
- if (!Context->ServerAddrAndProto) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- }
- SHELL_FREE_NON_NULL (Context->Uri);
- StringSize = AsciiStrSize (Location) * sizeof (CHAR16);
- Context->Uri = AllocateZeroPool (StringSize);
- if (!Context->Uri) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Error;
- }
- //
- // Now make changes to the Uri part.
- //
- Status = AsciiStrToUnicodeStrS (
- (CONST CHAR8 *)Location,
- Context->Uri,
- StringSize
- );
- Error:
- SHELL_FREE_NON_NULL (Tmp);
- SHELL_FREE_NON_NULL (Url);
- return Status;
- }
- /**
- Message parser callback.
- Save a portion of HTTP body.
- @param[in] EventType Type of event. Can be either
- OnComplete or OnData.
- @param[in] Data A pointer to the buffer with data.
- @param[in] Length Data length of this portion.
- @param[in] Context A pointer to the HTTP download context.
- @retval EFI_SUCCESS The portion was processed successfully.
- @retval Other Error returned by SavePortion.
- **/
- STATIC
- EFI_STATUS
- EFIAPI
- ParseMsg (
- IN HTTP_BODY_PARSE_EVENT EventType,
- IN CHAR8 *Data,
- IN UINTN Length,
- IN VOID *Context
- )
- {
- if ( (Data == NULL)
- || (EventType == BodyParseEventOnComplete)
- || (Context == NULL))
- {
- return EFI_SUCCESS;
- }
- return SavePortion (Context, Length, Data);
- }
- /**
- Get HTTP server response and collect the whole body as a file.
- Set appropriate status in Context (REQ_OK, REQ_REPEAT, REQ_ERROR).
- Note that even if HTTP server returns an error code, it might send
- the body as well. This body will be collected in the resultant file.
- @param[in] Context A pointer to the HTTP download context.
- @param[in] DownloadUrl A pointer to the fully qualified URL to download.
- @retval EFI_SUCCESS Valid file. Body successfully collected.
- @retval EFI_HTTP_ERROR Response is a valid HTTP response, but the
- HTTP server
- indicated an error (HTTP code >= 400).
- Response body MAY contain full
- HTTP server response.
- @retval Others Error getting the reponse from the HTTP server.
- Response body is not collected.
- **/
- STATIC
- EFI_STATUS
- GetResponse (
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN CHAR16 *DownloadUrl
- )
- {
- EFI_HTTP_RESPONSE_DATA ResponseData;
- EFI_HTTP_MESSAGE ResponseMessage;
- EFI_HTTP_HEADER *Header;
- EFI_STATUS Status;
- VOID *MsgParser;
- EFI_TIME StartTime;
- EFI_TIME EndTime;
- CONST CHAR16 *Desc;
- UINTN ElapsedSeconds;
- BOOLEAN IsTrunked;
- BOOLEAN CanMeasureTime;
- ZeroMem (&ResponseData, sizeof (ResponseData));
- ZeroMem (&ResponseMessage, sizeof (ResponseMessage));
- ZeroMem (&Context->ResponseToken, sizeof (Context->ResponseToken));
- IsTrunked = FALSE;
- ResponseMessage.Body = Context->Buffer;
- Context->ResponseToken.Status = EFI_SUCCESS;
- Context->ResponseToken.Message = &ResponseMessage;
- Context->ContentLength = 0;
- Context->Status = REQ_OK;
- Status = EFI_SUCCESS;
- MsgParser = NULL;
- ResponseData.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS;
- ResponseMessage.Data.Response = &ResponseData;
- Context->ResponseToken.Event = NULL;
- CanMeasureTime = FALSE;
- if (Context->Flags & DL_FLAG_TIME) {
- ZeroMem (&StartTime, sizeof (StartTime));
- CanMeasureTime = !EFI_ERROR (gRT->GetTime (&StartTime, NULL));
- }
- do {
- SHELL_FREE_NON_NULL (ResponseMessage.Headers);
- ResponseMessage.HeaderCount = 0;
- gResponseCallbackComplete = FALSE;
- ResponseMessage.BodyLength = Context->BufferSize;
- if (ShellGetExecutionBreakFlag ()) {
- Status = EFI_ABORTED;
- break;
- }
- if (!Context->ContentDownloaded && !Context->ResponseToken.Event) {
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- ResponseCallback,
- Context,
- &Context->ResponseToken.Event
- );
- ASSERT_EFI_ERROR (Status);
- } else {
- ResponseMessage.Data.Response = NULL;
- }
- if (EFI_ERROR (Status)) {
- break;
- }
- Status = Context->Http->Response (Context->Http, &Context->ResponseToken);
- if (EFI_ERROR (Status)) {
- break;
- }
- Status = WaitForCompletion (Context, &gResponseCallbackComplete);
- if (EFI_ERROR (Status) && ResponseMessage.HeaderCount) {
- Status = EFI_SUCCESS;
- }
- if (EFI_ERROR (Status)) {
- Context->Http->Cancel (Context->Http, &Context->ResponseToken);
- break;
- }
- if (!Context->ContentDownloaded) {
- if (NEED_REDIRECTION (ResponseData.StatusCode)) {
- //
- // Need to repeat the request with new Location (server redirected).
- //
- Context->Status = REQ_NEED_REPEAT;
- Header = HttpFindHeader (
- ResponseMessage.HeaderCount,
- ResponseMessage.Headers,
- "Location"
- );
- if (Header) {
- Status = SetHostURI (Header->FieldValue, Context, DownloadUrl);
- if (Status == EFI_NO_MAPPING) {
- PRINT_HII (
- STRING_TOKEN (STR_HTTP_ERR_STATUSCODE),
- Context->ServerAddrAndProto,
- L"Recursive HTTP server relocation",
- Context->Uri
- );
- }
- } else {
- //
- // Bad reply from the server. Server must specify the location.
- // Indicate that resource was not found, and no body collected.
- //
- Status = EFI_NOT_FOUND;
- }
- Context->Http->Cancel (Context->Http, &Context->ResponseToken);
- break;
- }
- //
- // Init message-body parser by header information.
- //
- if (!MsgParser) {
- Status = HttpInitMsgParser (
- ResponseMessage.Data.Request->Method,
- ResponseData.StatusCode,
- ResponseMessage.HeaderCount,
- ResponseMessage.Headers,
- ParseMsg,
- Context,
- &MsgParser
- );
- if (EFI_ERROR (Status)) {
- break;
- }
- }
- //
- // If it is a trunked message, rely on the parser.
- //
- Header = HttpFindHeader (
- ResponseMessage.HeaderCount,
- ResponseMessage.Headers,
- "Transfer-Encoding"
- );
- IsTrunked = (Header && !AsciiStrCmp (Header->FieldValue, "chunked"));
- HttpGetEntityLength (MsgParser, &Context->ContentLength);
- if ( (ResponseData.StatusCode >= HTTP_STATUS_400_BAD_REQUEST)
- && (ResponseData.StatusCode != HTTP_STATUS_308_PERMANENT_REDIRECT))
- {
- //
- // Server reported an error via Response code.
- // Collect the body if any.
- //
- if (!gHttpError) {
- gHttpError = TRUE;
- Desc = ErrStatusDesc[ResponseData.StatusCode -
- HTTP_STATUS_400_BAD_REQUEST];
- PRINT_HII (
- STRING_TOKEN (STR_HTTP_ERR_STATUSCODE),
- Context->ServerAddrAndProto,
- Desc,
- Context->Uri
- );
- //
- // This gives an RFC HTTP error.
- //
- Context->Status = ShellStrToUintn (Desc);
- Status = ENCODE_ERROR (Context->Status);
- }
- }
- }
- //
- // Do NOT try to parse an empty body.
- //
- if (ResponseMessage.BodyLength || IsTrunked) {
- Status = HttpParseMessageBody (
- MsgParser,
- ResponseMessage.BodyLength,
- ResponseMessage.Body
- );
- }
- } while ( !HttpIsMessageComplete (MsgParser)
- && !EFI_ERROR (Status)
- && ResponseMessage.BodyLength);
- if ( (Context->Status != REQ_NEED_REPEAT)
- && (Status == EFI_SUCCESS)
- && CanMeasureTime)
- {
- if (!EFI_ERROR (gRT->GetTime (&EndTime, NULL))) {
- ElapsedSeconds = EfiTimeToEpoch (&EndTime) - EfiTimeToEpoch (&StartTime);
- Print (
- L",%a%Lus\n",
- ElapsedSeconds ? " " : " < ",
- ElapsedSeconds > 1 ? (UINT64)ElapsedSeconds : 1
- );
- }
- }
- SHELL_FREE_NON_NULL (MsgParser);
- if (Context->ResponseToken.Event) {
- gBS->CloseEvent (Context->ResponseToken.Event);
- ZeroMem (&Context->ResponseToken, sizeof (Context->ResponseToken));
- }
- return Status;
- }
- /**
- Worker function that downloads the data of a file from an HTTP server given
- the path of the file and its size.
- @param[in] Context A pointer to the HTTP download context.
- @param[in] ControllerHandle The handle of the network interface controller
- @param[in] NicName NIC name
- @retval EFI_SUCCESS The file was downloaded.
- @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
- #return EFI_HTTP_ERROR The server returned a valid HTTP error.
- Examine the mLocalFilePath file
- to get error body.
- @retval Others The downloading of the file from the server
- failed.
- **/
- STATIC
- EFI_STATUS
- DownloadFile (
- IN HTTP_DOWNLOAD_CONTEXT *Context,
- IN EFI_HANDLE ControllerHandle,
- IN CHAR16 *NicName
- )
- {
- EFI_STATUS Status;
- CHAR16 *DownloadUrl;
- UINTN UrlSize;
- EFI_HANDLE HttpChildHandle;
- ASSERT (Context);
- if (Context == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- DownloadUrl = NULL;
- HttpChildHandle = NULL;
- Context->Buffer = AllocatePool (Context->BufferSize);
- if (Context->Buffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
- //
- // Open the file.
- //
- if (!EFI_ERROR (ShellFileExists (mLocalFilePath))) {
- ShellDeleteFileByName (mLocalFilePath);
- }
- Status = ShellOpenFileByName (
- mLocalFilePath,
- &mFileHandle,
- EFI_FILE_MODE_CREATE |
- EFI_FILE_MODE_WRITE |
- EFI_FILE_MODE_READ,
- 0
- );
- if (EFI_ERROR (Status)) {
- PRINT_HII_APP (STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), mLocalFilePath);
- goto ON_EXIT;
- }
- do {
- SHELL_FREE_NON_NULL (DownloadUrl);
- CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle);
- Status = CreateServiceChildAndOpenProtocol (
- ControllerHandle,
- &gEfiHttpServiceBindingProtocolGuid,
- &gEfiHttpProtocolGuid,
- &HttpChildHandle,
- (VOID **)&Context->Http
- );
- if (EFI_ERROR (Status)) {
- PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_OPEN_PROTOCOL), NicName, Status);
- goto ON_EXIT;
- }
- Status = Context->Http->Configure (Context->Http, &Context->HttpConfigData);
- if (EFI_ERROR (Status)) {
- PRINT_HII (STRING_TOKEN (STR_HTTP_ERR_CONFIGURE), NicName, Status);
- goto ON_EXIT;
- }
- UrlSize = 0;
- DownloadUrl = StrnCatGrow (
- &DownloadUrl,
- &UrlSize,
- Context->ServerAddrAndProto,
- StrLen (Context->ServerAddrAndProto)
- );
- if (Context->Uri[0] != L'/') {
- DownloadUrl = StrnCatGrow (
- &DownloadUrl,
- &UrlSize,
- L"/",
- StrLen (Context->ServerAddrAndProto)
- );
- }
- DownloadUrl = StrnCatGrow (
- &DownloadUrl,
- &UrlSize,
- Context->Uri,
- StrLen (Context->Uri)
- );
- PRINT_HII (STRING_TOKEN (STR_HTTP_DOWNLOADING), DownloadUrl);
- Status = SendRequest (Context, DownloadUrl);
- if (Status) {
- goto ON_EXIT;
- }
- Status = GetResponse (Context, DownloadUrl);
- if (Status) {
- goto ON_EXIT;
- }
- } while (Context->Status == REQ_NEED_REPEAT);
- if (Context->Status) {
- Status = ENCODE_ERROR (Context->Status);
- }
- ON_EXIT:
- //
- // Close the file.
- //
- if (mFileHandle != NULL) {
- if (EFI_ERROR (Status) && !(Context->Flags & DL_FLAG_KEEP_BAD)) {
- ShellDeleteFile (&mFileHandle);
- } else {
- ShellCloseFile (&mFileHandle);
- }
- }
- SHELL_FREE_NON_NULL (DownloadUrl);
- SHELL_FREE_NON_NULL (Context->Buffer);
- CLOSE_HTTP_HANDLE (ControllerHandle, HttpChildHandle);
- return Status;
- }
- /**
- Retrive HII package list from ImageHandle and publish to HII database.
- @param[in] ImageHandle The image handle of the process.
- @retval HII handle.
- **/
- EFI_HII_HANDLE
- InitializeHiiPackage (
- IN EFI_HANDLE ImageHandle
- )
- {
- EFI_STATUS Status;
- EFI_HII_PACKAGE_LIST_HEADER *PackageList;
- EFI_HII_HANDLE HiiHandle;
- //
- // Retrieve HII package list from ImageHandle.
- //
- Status = gBS->OpenProtocol (
- ImageHandle,
- &gEfiHiiPackageListProtocolGuid,
- (VOID **)&PackageList,
- ImageHandle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
- //
- // Publish HII package list to HII Database.
- //
- Status = gHiiDatabase->NewPackageList (
- gHiiDatabase,
- PackageList,
- NULL,
- &HiiHandle
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
- return HiiHandle;
- }
|