From 1e86e9735efaeace6e9a8b1930e15e28c33f750e Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Tue, 27 Oct 2020 21:10:40 -0500 Subject: [PATCH] :recycle: Towards response headers and status code --- Cargo.toml | 3 +++ src/bin/relay.rs | 7 +++++- src/bin/server.rs | 63 +++++++++++++++++++++++++++++++++++++---------- src/http_serde.rs | 4 +-- todo.md | 1 + 5 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 99d8f74..d2bb7bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,9 +9,12 @@ edition = "2018" [dependencies] +base64 = "0.12" futures = "0.3" http = "0.2" hyper = "0.13" +lazy_static = "1.4" +regex = "1" reqwest = { version = "0.10.8", features = ["stream"] } rmp-serde = "0.14.4" serde = {version = "1.0", features = ["derive"]} diff --git a/src/bin/relay.rs b/src/bin/relay.rs index a940688..f98f44f 100644 --- a/src/bin/relay.rs +++ b/src/bin/relay.rs @@ -173,7 +173,12 @@ async fn handle_http_request ( match r.await { Ok (Message::HttpResponseResponseStream (body)) => { println! ("Step 7"); - status_reply (StatusCode::OK, body) + + Response::builder () + .status (StatusCode::OK) + .header ("Accept-Ranges", "bytes") + .body (body) + .unwrap () }, _ => status_reply (StatusCode::GATEWAY_TIMEOUT, "server didn't reply in time or somethin'"), } diff --git a/src/bin/server.rs b/src/bin/server.rs index ebad9e6..bc6d0c3 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -1,6 +1,7 @@ use std::{ convert::Infallible, error::Error, + io::SeekFrom, path::PathBuf, sync::Arc, time::Duration, @@ -10,6 +11,8 @@ use hyper::{ StatusCode, Uri, }; +use lazy_static::*; +use regex::Regex; use reqwest::{ Body, Client, @@ -25,6 +28,24 @@ use tokio::{ use ptth::http_serde::*; +fn parse_range_header (range_str: &str) -> (Option , Option ) { + lazy_static! { + static ref RE: Regex = Regex::new (r"^(\d+)-(\d+)$").expect ("Couldn't compile regex for Range header"); + } + + let caps = match RE.captures (range_str) { + Some (x) => x, + _ => return (None, None), + }; + let start = caps.get (1).map (|x| x.as_str ()); + let end = caps.get (2).map (|x| x.as_str ()); + + let start = start.map (|x| u64::from_str_radix (x, 10).ok ()).flatten (); + let end = end.map (|x| u64::from_str_radix (x, 10).ok ()).flatten (); + + (start, end) +} + #[tokio::main] async fn main () -> Result <(), Box > { let client = Arc::new (Client::new ()); @@ -73,6 +94,19 @@ async fn main () -> Result <(), Box > { let (req_id, uri) = (parts.id, parts.uri); println! ("Client requested {}", uri); + let mut range_start = None; + let mut range_end = None; + + for (k, v) in parts.headers.iter () { + let v = std::str::from_utf8 (v).unwrap (); + println! ("{}: {}", k, v); + + if k == "range" { + let (start, end) = parse_range_header (v); + range_start = start; + range_end = end; + } + } println! ("Step 4/5"); @@ -80,22 +114,23 @@ async fn main () -> Result <(), Box > { let client = client.clone (); tokio::spawn (async move { let (tx, rx) = channel (2); - //let rx: Receiver > = rx; + + let mut path = PathBuf::from ("/home/user"); + path.push (&uri [1..]); + let mut f = File::open (path).await.unwrap (); + + if let Some (start) = range_start { + f.seek (SeekFrom::Start (start)).await.unwrap (); + } tokio::spawn (async move { - //let path = "/home/user/projects/2020/ptth/README.md"; + //println! ("Opening file {:?}", path); - let mut path = PathBuf::from ("/home/user"); - path.push (&uri [1..]); - - println! ("Opening file {:?}", path); - - let mut f = File::open (path).await.unwrap (); let mut tx = tx; - let mut bytes_sent = 0; + //let mut bytes_sent = 0; loop { - let mut buffer = vec! [0u8; 4096]; + let mut buffer = vec! [0u8; 65_536]; let bytes_read = f.read (&mut buffer).await.unwrap (); buffer.truncate (bytes_read); @@ -104,10 +139,12 @@ async fn main () -> Result <(), Box > { break; } - tx.send (Ok::<_, Infallible> (buffer)).await.unwrap (); - bytes_sent += bytes_read; + if tx.send (Ok::<_, Infallible> (buffer)).await.is_err () { + break; + } - println! ("Sent {} bytes", bytes_sent); + //bytes_sent += bytes_read; + //println! ("Sent {} bytes", bytes_sent); delay_for (Duration::from_millis (50)).await; } diff --git a/src/http_serde.rs b/src/http_serde.rs index d28e1f0..9799b9d 100644 --- a/src/http_serde.rs +++ b/src/http_serde.rs @@ -62,7 +62,7 @@ pub enum StatusCode { Ok, NotFound, } - +/* impl TryFrom for StatusCode { type Error = Error; @@ -74,7 +74,7 @@ impl TryFrom for StatusCode { } } } - +*/ impl From for hyper::StatusCode { fn from (x: StatusCode) -> Self { match x { diff --git a/todo.md b/todo.md index 68adf6a..dfeb27b 100644 --- a/todo.md +++ b/todo.md @@ -1,2 +1,3 @@ +- Figure out how to pack response status / headers into request body - Byte range request header - Content-Length response header