use crate::{ffi::http_request_v1 as ffi, Error, ErrorCode};
use std::{
borrow::Cow,
future::Future,
pin::Pin,
string::FromUtf8Error,
task::{Context, Poll},
};
#[doc(hidden)]
pub use ffi::API as FFI_API;
pub use ffi::Method;
pub struct Response {
pub status_code: u16,
bytes: Vec<u8>,
}
impl Response {
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn as_text(&self) -> Result<String, FromUtf8Error> {
String::from_utf8(self.bytes.clone())
}
pub fn as_text_lossy(&self) -> Cow<'_, str> {
String::from_utf8_lossy(&self.bytes)
}
}
struct RequestFuture(Result<ffi::RequestHandle, ErrorCode>);
pub type ResponseResult = Result<Response, Error>;
impl Future for RequestFuture {
type Output = ResponseResult;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.0 {
Ok(handle) => {
let mut status: u32 = 0;
if let Err(error_code) = ffi::is_ready(handle, &mut status) {
return Poll::Ready(Err(Error::from(error_code)));
}
if status != ffi::STATUS_PENDING {
match ffi::retrieve(handle) {
Ok(bytes) => {
assert!(u16::try_from(status).is_ok());
let response = Response {
bytes,
status_code: status as u16,
};
Poll::Ready(Ok(response))
}
Err(error_code) => Poll::Ready(Err(Error::from(error_code))),
}
} else {
Poll::Pending
}
}
Err(error_code) => Poll::Ready(Err(Error::from(error_code))),
}
}
}
pub fn http_request(
method: Method,
url: &str,
body: &[u8],
) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(method, url, body))
}
pub fn http_get(url: &str) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Get, url, &[]))
}
pub fn http_post(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Post, url, body))
}
pub fn http_put(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Put, url, body))
}
pub fn http_delete(url: &str) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Delete, url, &[]))
}
pub fn http_patch(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Patch, url, body))
}
pub fn http_head(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Head, url, body))
}
pub fn http_options(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Options, url, body))
}
pub fn http_trace(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Trace, url, body))
}
pub fn http_connect(url: &str, body: &[u8]) -> impl Future<Output = ResponseResult> {
RequestFuture(ffi::request(ffi::Method::Connect, url, body))
}