pub struct HttpAdapter {
listener: Option<TcpListener>,
bind_addr: SocketAddr,
}
impl HttpAdapter {
#[must_use]
pub fn new(bind_addr: SocketAddr) -> Self {
Self {
listener: None,
bind_addr,
}
}
pub async fn bind(&mut self) -> Result<(), ProtocolError> {
let listener = TcpListener::bind(self.bind_addr)
.await
.map_err(ProtocolError::IoError)?;
info!("HTTP server bound to {}", self.bind_addr);
self.listener = Some(listener);
Ok(())
}
pub async fn accept(&mut self) -> Result<(TcpStream, SocketAddr), ProtocolError> {
let listener = self
.listener
.as_ref()
.ok_or_else(|| ProtocolError::InvalidFormat("HTTP adapter not bound".to_string()))?;
listener.accept().await.map_err(ProtocolError::IoError)
}
pub fn from_stream(stream: TcpStream, remote_addr: SocketAddr) -> HttpStreamAdapter {
HttpStreamAdapter {
stream: Some(stream),
remote_addr,
}
}
}
#[async_trait]
impl ProtocolAdapter for HttpAdapter {
type Input = HttpInput;
type Output = HttpOutput;
fn protocol(&self) -> Protocol {
Protocol::Http
}
async fn decode(&self, input: Self::Input) -> Result<UnifiedRequest, ProtocolError> {
debug!("Decoding HTTP input");
let (request, remote_addr) = match input {
HttpInput::Request {
request,
remote_addr,
} => (request, remote_addr),
HttpInput::Raw {
stream: _stream,
remote_addr: _remote_addr,
} => {
return Err(ProtocolError::HttpError(
"Raw stream parsing not implemented".to_string(),
));
}
};
let (parts, body) = request.into_parts();
let user_agent = parts
.headers
.get("user-agent")
.and_then(|h| h.to_str().ok())
.map(std::string::ToString::to_string);
let http_context = HttpContext {
remote_addr: Some(remote_addr.to_string()),
user_agent,
};
let body_bytes = body
.collect()
.await
.map_err(|e| ProtocolError::DecodeError(format!("Failed to read body: {e}")))?
.to_bytes();
let method = parts.method.clone();
let uri = parts.uri.clone();
let unified_request = UnifiedRequest::new(parts.method, parts.uri.to_string())
.with_body(Body::from(body_bytes.to_vec()))
.with_extension("protocol", Protocol::Http)
.with_extension("http_context", http_context);
let mut final_request = unified_request;
for (name, value) in &parts.headers {
if let Ok(value_str) = value.to_str() {
final_request = final_request.with_header(name.as_str(), value_str);
}
}
debug!(
method = %method,
uri = %uri,
remote_addr = %remote_addr,
"Decoded HTTP request"
);
Ok(final_request)
}
async fn encode(&self, response: UnifiedResponse) -> Result<Self::Output, ProtocolError> {
debug!(status = %response.status, "Encoding HTTP response");
let mut http_response = Response::builder().status(response.status);
for (name, value) in &response.headers {
http_response = http_response.header(name, value);
}
let final_response = http_response.body(response.body).map_err(|e| {
ProtocolError::EncodeError(format!("Failed to build HTTP response: {e}"))
})?;
Ok(HttpOutput::Response(final_response))
}
}