Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasbishop committed Jan 11, 2025
1 parent 9b11dfa commit d8f7adc
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 21 deletions.
4 changes: 2 additions & 2 deletions uefi-raw/src/protocol/network/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ impl Default for HttpAccessPoint {
pub struct HttpToken {
pub event: Event,
pub status: Status,
pub message: *const HttpMessage,
pub message: *mut HttpMessage,
}

impl Default for HttpToken {
fn default() -> Self {
Self {
event: ptr::null_mut(),
status: Status::SUCCESS,
message: ptr::null(),
message: ptr::null_mut(),
}
}
}
Expand Down
12 changes: 7 additions & 5 deletions uefi-test-runner/src/proto/network/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ pub fn test() {

http.send_request_sync(HttpRequest {
method: HttpMethod::GET,
url: cstr16!("http://example.com"),
headers: &[HttpHeader::new(
cstr8!("Host"),
cstr8!("http://example.com"),
)],
//url: cstr16!("http://example.com/"),
url: cstr16!("http://example.com/"),
headers: &[
HttpHeader::new(cstr8!("Host"), cstr8!("example.com")),
HttpHeader::new(cstr8!("Accept"), cstr8!("*/*")),
HttpHeader::new(cstr8!("User-Agent"), cstr8!("uefi-rs test runner")),
],
body: &[],
})
.unwrap();
Expand Down
2 changes: 1 addition & 1 deletion uefi/src/data_types/strs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ impl fmt::Debug for CStr8 {

impl fmt::Display for CStr8 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for c in self.0.iter() {
for c in &self.0[..&self.0.len() - 1] {
<Char8 as fmt::Display>::fmt(c, f)?;
}
Ok(())
Expand Down
135 changes: 122 additions & 13 deletions uefi/src/proto/network/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@

use crate::boot::{self, EventType, MemoryType, Tpl};
use crate::data_types::Ipv4Address;
use crate::{CStr16, CStr8, Event, Handle, Result, Status, StatusExt};
use crate::{CStr16, CStr8, Error, Event, Handle, Result, Status, StatusExt};
use core::ffi::c_void;
use core::mem;
use core::ops::Deref;
use core::ptr::{self, NonNull};
use core::time::Duration;
use log::error;
use log::{error, info};
use uefi_macros::unsafe_protocol;
use uefi_raw::protocol::driver::ServiceBindingProtocol;
use uefi_raw::protocol::network::http as http_raw;
use uefi_raw::protocol::network::http::{HttpResponseData, HttpStatusCode};

// TODO, not pub for most of these
pub use uefi_raw::protocol::network::http::{
Expand Down Expand Up @@ -107,43 +108,151 @@ impl Http {
dst.field_value = request.headers[i].value.as_ptr().cast();
}

let message = HttpMessage {
let mut message = HttpMessage {
data: HttpRequestOrResponse {
request: &request_data,
},
header_count: request.headers.len(),
headers,
body_length: request.body.len(),
// TODO: body: request.body.as_ptr().cast(),
body: ptr::null(),
body: request.body.as_ptr().cast(),
};

let mut is_done = false;
let is_done_ptr: *mut bool = &mut is_done;
let is_done_ptr = ptr::from_mut(&mut is_done);

let event = unsafe {
boot::create_event(
EventType::NOTIFY_SIGNAL,
Tpl::NOTIFY,
Some(request_done_callback),
Some(done_callback),
NonNull::new(is_done_ptr.cast()),
)?
};

let mut token = HttpToken {
event: event.as_ptr(),
status: Status::SUCCESS,
message: &message,
status: Status::NOT_READY,
message: &mut message,
};
let token_ptr = ptr::from_mut(&mut token);
// TODO
log::info!("token: {token:?}");
log::info!("message: {:?}", unsafe { &*token.message });
info!("token: {token:?}");
info!("message: {:?}", unsafe { &*token.message });

unsafe { (self.0.request)(&mut self.0, &mut token) }.to_result()
unsafe { (self.0.request)(&mut self.0, &mut token) }.to_result()?;

// Wait for the request to finish.
while unsafe { !is_done_ptr.read_volatile() } {
info!("not yet"); // TODO
self.poll()?;
}

// TODO
info!("request done");

// Check token status.
let status = unsafe { token_ptr.read_volatile() }.status;
if status != Status::SUCCESS {
return Err(Error::from(status));
}

// TODO: clean up the event.

self.read_response()
}

// TODO: api
fn read_response(&mut self) -> Result<()> {
// TODO: dedup with request
let mut is_done = false;
let is_done_ptr = ptr::from_mut(&mut is_done);

let event = unsafe {
boot::create_event(
EventType::NOTIFY_SIGNAL,
Tpl::NOTIFY,
Some(done_callback),
NonNull::new(is_done_ptr.cast()),
)?
};

let mut response = HttpResponseData {
status_code: HttpStatusCode::STATUS_UNSUPPORTED,
};

// TODO: make sure all allocations are freed.
// TODO: make alloc required?
let body_len = 4096;
let body = boot::allocate_pool(
// TODO: maybe have a global somewhere for memtype?
MemoryType::LOADER_DATA,
// TODO: use page alloc instead?
body_len,
)?;

let mut message = HttpMessage {
data: HttpRequestOrResponse {
response: &mut response,
},
// TODO
header_count: 0,
headers: ptr::null_mut(),
body_length: body_len,
body: body.as_ptr().cast(),
};

let mut token = HttpToken {
event: event.as_ptr(),
status: Status::NOT_READY,
message: &mut message,
};
let token_ptr = ptr::from_mut(&mut token);

info!("awaiting response");
unsafe { (self.0.response)(&mut self.0, &mut token) }.to_result()?;
info!("response call done");

// Wait for the response to finish.
while unsafe { !is_done_ptr.read_volatile() } {
info!("not yet"); // TODO
self.poll()?;
}

// TODO: handle body buf too small.

// TODO
info!("response done");

info!("http code: {:?}", unsafe {
ptr::from_mut(&mut response).read_volatile()
});
info!("num headers: {}", message.header_count);
for i in 0..message.header_count {
let header = unsafe { message.headers.add(i) };
let header = unsafe { &*header };
let name = unsafe { CStr8::from_ptr(header.field_name.cast()) };
let val = unsafe { CStr8::from_ptr(header.field_value.cast()) };
info!("header {i}: {name}: {val}");
}

// Check token status.
let token = unsafe { token_ptr.read_volatile() };
let status = token.status;
if status != Status::SUCCESS {
return Err(Error::from(status));
}

todo!()
}

// TODO: pub?
fn poll(&mut self) -> Result<()> {
unsafe { (self.0.poll)(&mut self.0) }.to_result()
}
}

unsafe extern "efiapi" fn request_done_callback(_event: Event, context: Option<NonNull<c_void>>) {
unsafe extern "efiapi" fn done_callback(_event: Event, context: Option<NonNull<c_void>>) {
if let Some(context) = context {
let is_done: *mut bool = context.as_ptr().cast();
*is_done = true;
Expand Down

0 comments on commit d8f7adc

Please sign in to comment.