mod common;
use std::convert::Infallible;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use bytes::Bytes;
use iroh_http_core::{fetch, serve, Body, RemoteNodeId, ServeOptions};
use tower::Service;
#[derive(Clone)]
struct EchoPeerService;
impl Service<hyper::Request<Body>> for EchoPeerService {
type Response = hyper::Response<Body>;
type Error = Infallible;
type Future =
Pin<Box<dyn std::future::Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: hyper::Request<Body>) -> Self::Future {
let peer = req
.extensions()
.get::<RemoteNodeId>()
.map(|r| (*r.0).clone())
.unwrap_or_default();
let path = req.uri().path().to_string();
Box::pin(async move {
let body = format!("path={path} peer={peer}");
Ok(hyper::Response::builder()
.status(200)
.header("content-type", "text/plain")
.body(Body::full(Bytes::from(body)))
.expect("static response args are valid"))
})
}
}
#[tokio::test]
async fn pure_rust_serve_round_trips_with_peer_id_extension() {
let (server_ep, client_ep) = common::make_pair().await;
let server_id = common::node_id(&server_ep);
let addrs = common::server_addrs(&server_ep);
let client_id = common::node_id(&client_ep);
let _handle = serve(server_ep.clone(), ServeOptions::default(), EchoPeerService);
let res = fetch(
&client_ep,
&server_id,
"/hello-pure",
"GET",
&[],
None,
None,
Some(&addrs),
None,
true,
None, )
.await
.expect("fetch ok");
assert_eq!(res.status, 200);
let mut body = Vec::new();
while let Some(chunk) = client_ep
.handles()
.next_chunk(res.body_handle)
.await
.expect("chunk read ok")
{
body.extend_from_slice(&chunk);
}
let body = String::from_utf8(body).expect("utf8 body");
assert!(body.contains("path=/hello-pure"), "body: {body}");
assert!(body.contains(&format!("peer={client_id}")), "body: {body}");
let _ = Arc::new(());
}