chiark / gitweb /
own http body type
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 22 Aug 2021 15:41:02 +0000 (16:41 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 22 Aug 2021 15:41:02 +0000 (16:41 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock
Cargo.toml
server/suser.rs
server/sweb.rs
src/prelude.rs
src/queue.rs

index 9b65d3e7c6a3ea31d51d19f6b86cdc5b36fb745f..593f1e46c5c8748ec78ede38a5320621f944dbb1 100644 (file)
@@ -431,6 +431,7 @@ dependencies = [
  "memchr",
  "mime",
  "parking_lot",
+ "pin-project-lite",
  "regex",
  "sha2",
  "structopt",
index b5f5c13da8428726ea11f5d919d123b1d3b95ad1..54575e5a66e92ca5d31ad53ea81b7500d333702f 100644 (file)
@@ -41,6 +41,7 @@ regex = "1.5"
 lazy_static = "1.4"
 log = "0.4"
 memchr = "2"
+pin-project-lite = "0.2"
 sha2 = "0.9"
 structopt = "0.3"
 subtle = "2"
index 69881e54f980752286d7ca0a67ead97a212b3849..48c8be5b8af186f89321994bd04b076c39c341de 100644 (file)
@@ -51,7 +51,7 @@ pub async fn run(global: Arc<Global>,
       }
     } {
       let response = WebResponse {
-        data: Ok(vec![ /* xxx */ ]),
+        data: Ok(default()),
         warnings: default(),
       };
 
index d4e825e0886f60b093cf99e455379cc38b6a6153..0176e46afba58b28d0add5581b7b073d1e0b7fb5 100644 (file)
@@ -30,15 +30,16 @@ pub struct WebResponse {
   pub data: Result<WebResponseData, AE>,
 }
 
-pub type WebResponseData = Vec<u8>;
+pub type WebResponseData = FrameQueueBuf;
+pub type WebResponseBody = BufBody<FrameQueueBuf>;
 
 pub async fn handle(
   conn: Arc<String>,
   global: Arc<Global>,
   req: hyper::Request<hyper::Body>
-) -> Result<hyper::Response<hyper::Body>, hyper::http::Error> {
+) -> Result<hyper::Response<WebResponseBody>, hyper::http::Error> {
   if req.method() == Method::GET {
-    let mut resp = hyper::Response::new(hyper::Body::from("hippotat\r\n"));
+    let mut resp = hyper::Response::new(BufBody::display("hippotat\r\n"));
     resp.headers_mut().insert(
       "Content-Type",
       "text/plain; charset=US-ASCII".try_into().unwrap()
@@ -149,7 +150,7 @@ pub async fn handle(
     //dbg!(DumpHex(hmac_got), hmac_ok, client_exists);
     if ! bool::from(hmac_ok & client_exists) {
       debug!("{} rejected client {}", &conn, &client_name);
-      let body = hyper::Body::from("Not authorised\r\n");
+      let body = BufBody::display("Not authorised\r\n");
       return Ok(
         hyper::Response::builder()
           .status(hyper::StatusCode::FORBIDDEN)
@@ -208,7 +209,7 @@ pub async fn handle(
              &warnings.warnings);
     }
 
-    let data = hyper::Body::from(data);
+    let data = BufBody::new(data);
     Ok::<_,AE>(
       hyper::Response::builder()
         .header("Content-Type", r#"application/octet-stream"#)
@@ -223,6 +224,6 @@ pub async fn handle(
     hyper::Response::builder()
       .status(hyper::StatusCode::BAD_REQUEST)
       .header("Content-Type", r#"text/plain; charset="utf-8""#)
-      .body(errmsg.into())
+      .body(BufBody::display(errmsg))
   })
 }
index 228509bbbaf6100f02575a976af6c468f4e590bf..c7c53e15012320cbfb205c650daf56995a4eff98 100644 (file)
@@ -29,7 +29,7 @@ pub use cervine::Cow as Cervine;
 pub use extend::ext;
 pub use fehler::{throw, throws};
 pub use futures::{poll, future, FutureExt, StreamExt, TryStreamExt};
-pub use hyper::body::{Bytes, Buf};
+pub use hyper::body::{Bytes, Buf, HttpBody};
 pub use hyper::{Method, Uri};
 pub use hyper_tls::HttpsConnector;
 pub use ipnet::IpNet;
@@ -38,6 +38,7 @@ pub use lazy_regex::{regex_captures, regex_is_match, regex_replace_all};
 pub use lazy_static::lazy_static;
 pub use log::{trace, debug, info, warn, error};
 pub use memchr::memmem;
+pub use pin_project_lite::pin_project;
 pub use structopt::StructOpt;
 pub use subtle::ConstantTimeEq;
 pub use thiserror::Error;
index 9deb48b584ef9a8313bff5908f685f11d910a672..5e22de9fb21eebfa40366e8945be27a6e87a1d5a 100644 (file)
@@ -59,6 +59,7 @@ impl<E> QueueBuf<E> where E: AsRef<[u8]> {
     self.content += l;
   }
   pub fn is_empty(&self) -> bool { self.content == 0 }
+  pub fn len(&self) -> usize { self.content }
 }
 
 impl FrameQueueBuf {
@@ -70,6 +71,7 @@ impl FrameQueueBuf {
     self.queue.push_(Cervine::Borrowed(&SLIP_END_SLICE));
   }
   pub fn is_empty(&self) -> bool { self.queue.is_empty() }
+  pub fn len(&self) -> usize { self.queue.len() }
 }
 
 impl<E> Extend<E> for FrameQueueBuf where E: Into<Box<[u8]>> {
@@ -104,3 +106,33 @@ impl hyper::body::Buf for FrameQueueBuf {
   fn chunk(&self) -> &[u8] { self.queue.chunk() }
   fn advance(&mut self, cnt: usize) { self.queue.advance(cnt) }
 }
+
+pin_project!{
+  pub struct BufBody<B:Buf> {
+    body: Option<B>,
+  }
+}
+impl<B:Buf> BufBody<B> {
+  pub fn new(body: B) -> Self { Self { body: Some(body ) } }
+}
+impl BufBody<FrameQueueBuf> {
+  pub fn display<S:Display>(s: S) -> Self {
+    let s = s.to_string().into_bytes();
+    let mut buf: FrameQueueBuf = default();
+    buf.push(s);
+    Self::new(buf)
+  }
+}
+
+impl<B:Buf> HttpBody for BufBody<B> {
+  type Error = Void;
+  type Data = B;
+  fn poll_data(self: Pin<&mut Self>, _: &mut std::task::Context<'_>)
+               -> Poll<Option<Result<B, Void>>> {
+    Poll::Ready(Ok(self.project().body.take()).transpose())
+  }
+  fn poll_trailers(self: Pin<&mut Self>, _: &mut std::task::Context<'_>)
+ -> Poll<Result<Option<hyper::HeaderMap<hyper::header::HeaderValue>>, Void>> {
+    Poll::Ready(Ok(None))
+  }
+}