我正在使用 EDK2 环境开发 UEFI 应用程序,并尝试使用 UEFI API 执行 HTTP GET 请求。在 Http->Response 调用之后,该事件没有收到信号。如果我删除等待事件的部分,那么就会成功建立到服务器的连接,并且我能够毫无问题地接收 HTTP 响应标头。响应状态码为200 OK,表示请求成功。但在这种情况下身体仍然是空的。
如果您能提供有关如何解决此问题的任何见解或建议,我将不胜感激。我是否应该查看特定的 UEFI API 或步骤以确保我正确读取响应正文?任何帮助将不胜感激!
sendHttpRequest(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
EFI_STATUS Status;
EFI_HTTP_PROTOCOL *Http;
EFI_SERVICE_BINDING_PROTOCOL *HttpServiceBinding;
EFI_HANDLE HttpHandle = NULL;
EFI_HTTP_CONFIG_DATA HttpConfigData;
EFI_HTTP_REQUEST_DATA RequestData;
EFI_HTTP_RESPONSE_DATA ResponseData;
EFI_HTTP_TOKEN RequestToken, ResponseToken;
EFI_HTTP_MESSAGE RequestMessage, ResponseMessage;
EFI_HTTP_HEADER Headers[2];
CHAR16 *RequestUrl = L"http://" BOOT_SERVER_IP BOOT_CONFIG_PATH;
CHAR8 *Buffer;
BOOLEAN response_done;
BOOLEAN request_done;
UINTN Index;
Print(L"Starting HttpBootClient default DHCP example\r\n");
Status = gBS->LocateProtocol(&gEfiHttpServiceBindingProtocolGuid, NULL, (VOID **)&HttpServiceBinding);
if (EFI_ERROR(Status))
{
Print(L"Failed to locate HTTP service binding protocol: %r\n", Status);
return Status;
}
Status = HttpServiceBinding->CreateChild(HttpServiceBinding, &HttpHandle);
if (EFI_ERROR(Status))
{
Print(L"Failed to create HTTP child: %r\n", Status);
return Status;
}
Status = gBS->HandleProtocol(HttpHandle, &gEfiHttpProtocolGuid, (VOID **)&Http);
if (EFI_ERROR(Status))
{
Print(L"Failed to locate HTTP protocol: %r\n", Status);
return Status;
}
ZeroMem(&HttpConfigData, sizeof(HttpConfigData));
HttpConfigData.HttpVersion = HttpVersion11;
HttpConfigData.TimeOutMillisec = 500;
HttpConfigData.LocalAddressIsIPv6 = FALSE;
HttpConfigData.AccessPoint.IPv4Node = AllocatePool(sizeof(EFI_HTTPv4_ACCESS_POINT));
if (!HttpConfigData.AccessPoint.IPv4Node)
{
Print(L"Failed to allocate memory for the structure\n");
return EFI_OUT_OF_RESOURCES;
}
HttpConfigData.AccessPoint.IPv4Node->UseDefaultAddress = TRUE;
Status = Http->Configure(Http, &HttpConfigData);
if (EFI_ERROR(Status))
{
Print(L"Failed to configure HTTP protocol: %r\n", Status);
return Status;
}
ZeroMem(&RequestData, sizeof(RequestData));
RequestData.Method = HttpMethodGet;
RequestData.Url = RequestUrl;
ZeroMem(Headers, sizeof(Headers));
Headers[0].FieldName = "Host";
Headers[0].FieldValue = BOOT_SERVER_IP;
Headers[1].FieldName = "User-Agent";
Headers[1].FieldValue = "UEFI-Client";
ZeroMem(&RequestMessage, sizeof(RequestMessage));
RequestMessage.Data.Request = &RequestData;
RequestMessage.Headers = Headers;
RequestMessage.HeaderCount = 2;
RequestMessage.BodyLength = 0;
RequestMessage.Body = NULL;
ZeroMem(&RequestToken, sizeof(RequestToken));
RequestToken.Event = NULL;
RequestToken.Message = &RequestMessage;
request_done = FALSE;
Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, httpnotify, &request_done, &RequestToken.Event);
if (EFI_ERROR(Status))
{
Print(L"Failed to create request event: %r\n", Status);
Http->Configure(Http, NULL);
HttpServiceBinding->DestroyChild(HttpServiceBinding, HttpHandle);
return Status;
}
else{
Print(L"Event value : %p\n", RequestToken.Event);
}
Status = Http->Request(Http, &RequestToken);
if (EFI_ERROR(Status))
{
Print(L"Failed to send HTTP request: %r\n", Status);
Http->Configure(Http, NULL);
HttpServiceBinding->DestroyChild(HttpServiceBinding, HttpHandle);
return Status;
}
while (!request_done)
{
Status = Http->Poll(Http);
Print(L"HTTP Poll: %r\n", Status);
}
Print(L"Request Sent : %r\n", Status);
ZeroMem(&ResponseMessage, sizeof(ResponseMessage));
ResponseData.StatusCode = HTTP_STATUS_UNSUPPORTED_STATUS;
ResponseMessage.Data.Response = &ResponseData;
ResponseMessage.HeaderCount = 0;
ResponseMessage.Headers = NULL;
ResponseMessage.BodyLength = BUFFER_SIZE;
Status = gBS->AllocatePool(
EfiBootServicesData,
ResponseMessage.BodyLength,
(VOID **)&Buffer);
if (!Buffer)
{
Print(L"Failed to allocate memory for response body\n");
Http->Configure(Http, NULL);
HttpServiceBinding->DestroyChild(HttpServiceBinding, HttpHandle);
return EFI_OUT_OF_RESOURCES;
}
ZeroMem(Buffer, sizeof(BUFFER_SIZE));
ResponseMessage.Body = Buffer;
ZeroMem(&ResponseToken, sizeof(ResponseToken));
ResponseToken.Status = EFI_SUCCESS;
ResponseToken.Message = &ResponseMessage;
ResponseToken.Event = NULL;
response_done = FALSE;
Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, httpnotify, &response_done, &ResponseToken.Event);
if (EFI_ERROR(Status))
{
Print(L"Failed to create response event: %r\n", Status);
Http->Configure(Http, NULL);
HttpServiceBinding->DestroyChild(HttpServiceBinding, HttpHandle);
return Status;
}
else{
Print(L"Event value : %p\n", ResponseToken.Event);
}
Status = Http->Response(Http, &ResponseToken);
if (!EFI_ERROR(Status))
{
while (!response_done)
{
Status = Http->Poll(Http);
}
Print(L"HTTP response token: %r\n", ResponseToken.Status);
Print(L"Status Code : %d\n", ResponseToken.Message->Data.Response->StatusCode);
for (Index = 0; Index < ResponseMessage.HeaderCount; ++Index)
{
Print(L"%a: %a\n", ResponseMessage.Headers[Index].FieldName, ResponseMessage.Headers[Index].FieldValue);
}
if (ResponseMessage.Body && ResponseMessage.BodyLength > 0)
{
Print(L"HTTP Response Body: %a\n", Buffer);
Print(L"HTTP Response Body: %s\n", Buffer);
Print(L"Body Length: %d\n", ResponseMessage.BodyLength);
}
else
{
Print(L"Response body is empty\n");
}
}
else
{
Print(L"Failed to receive HTTP response: %r\n", Status);
}
if (Buffer)
{
FreePool(Buffer);
}
Http->Configure(Http, NULL);
HttpServiceBinding->DestroyChild(HttpServiceBinding, HttpHandle);
return EFI_SUCCESS;
}
服务器未发送“Content-Length”标头,这导致客户端无法确定何时终止请求。发送所需的标头后,问题就解决了。