use alloc::{string::String, vec::Vec};
use io_http::{
coroutine::*,
rfc9110::{
request::HttpRequest,
response::HttpResponse,
send::{HttpSendOutput, HttpSendYield},
},
rfc9112::send::{Http11Send, Http11SendError},
};
use log::trace;
use thiserror::Error;
use crate::coroutine::*;
#[derive(Debug)]
pub struct SendOk<T> {
pub response: HttpResponse,
pub keep_alive: bool,
pub body: T,
}
#[derive(Debug, Error)]
pub enum SendError {
#[error("WebDAV server returned HTTP {0}: {1}")]
HttpStatus(u16, String),
#[error("WebDAV server returned unexpected redirect")]
UnexpectedRedirect,
#[error(transparent)]
Send(#[from] Http11SendError),
}
#[derive(Debug)]
pub struct SendRaw {
state: State,
}
impl SendRaw {
pub fn new(request: HttpRequest) -> Self {
Self {
state: State::Send(Http11Send::new(request)),
}
}
}
impl WebdavCoroutine for SendRaw {
type Yield = WebdavYield;
type Return = Result<SendOk<Vec<u8>>, SendError>;
fn resume(&mut self, arg: Option<&[u8]>) -> WebdavCoroutineState<Self::Yield, Self::Return> {
trace!("sending request");
match &mut self.state {
State::Send(send) => {
let out = match send.resume(arg) {
HttpCoroutineState::Yielded(HttpSendYield::WantsRead) => {
return WebdavCoroutineState::Yielded(WebdavYield::WantsRead);
}
HttpCoroutineState::Yielded(HttpSendYield::WantsWrite(bytes)) => {
return WebdavCoroutineState::Yielded(WebdavYield::WantsWrite(bytes));
}
HttpCoroutineState::Yielded(HttpSendYield::WantsRedirect { .. }) => {
return WebdavCoroutineState::Complete(Err(SendError::UnexpectedRedirect));
}
HttpCoroutineState::Complete(Err(err)) => {
return WebdavCoroutineState::Complete(Err(err.into()));
}
HttpCoroutineState::Complete(Ok(out)) => out,
};
let HttpSendOutput {
response,
keep_alive,
..
} = out;
if !response.status.is_success() {
let body = String::from_utf8_lossy(&response.body).into_owned();
let err = SendError::HttpStatus(*response.status, body);
return WebdavCoroutineState::Complete(Err(err));
}
let body = response.body.clone();
WebdavCoroutineState::Complete(Ok(SendOk {
response,
keep_alive,
body,
}))
}
}
}
}
#[derive(Debug)]
enum State {
Send(Http11Send),
}