use alloc::{string::String, vec::Vec};
use io_http::{
coroutine::*,
rfc9110::{request::HttpRequest, send::HttpSendOutput},
rfc9112::send::{Http11Send, Http11SendError},
};
use log::trace;
use thiserror::Error;
use crate::{
coroutine::*,
rfc4918::{coroutine::WebdavRedirectYield, send::SendOk},
};
#[derive(Debug, Error)]
pub enum FollowRedirectsError {
#[error("WebDAV server returned HTTP {0}: {1}")]
HttpStatus(u16, String),
#[error(transparent)]
Send(#[from] Http11SendError),
}
#[derive(Debug)]
pub struct FollowRedirects {
state: State,
}
impl FollowRedirects {
pub fn new(request: HttpRequest) -> Self {
Self {
state: State::Send(Http11Send::new(request)),
}
}
}
impl WebdavCoroutine for FollowRedirects {
type Yield = WebdavRedirectYield;
type Return = Result<SendOk<Vec<u8>>, FollowRedirectsError>;
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(y) => {
return WebdavCoroutineState::Yielded(y.into());
}
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 = FollowRedirectsError::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),
}