diff --git a/Cargo.lock b/Cargo.lock index 6d5dd22..9ac93cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a01f9e0681608afa887d4269a0857ac4226f09ba5ceda25939e8391c9da610a" +checksum = "fb9c5d7ceb490d6565156ae1d4d467db17da1759425c65a2e36ac5e182e014e2" dependencies = [ "actix-codec", "actix-rt", @@ -33,7 +33,6 @@ dependencies = [ "brotli2", "bytes", "bytestring", - "cfg-if", "cookie", "derive_more", "encoding_rs", @@ -45,11 +44,13 @@ dependencies = [ "httparse", "itoa", "language-tags", + "local-channel", "log", "mime", "once_cell", "percent-encoding", "pin-project", + "pin-project-lite", "rand", "regex", "serde", @@ -86,9 +87,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b4e57bc1a3915e71526d128baf4323700bd1580bc676239e2298a4c5b001f18" +checksum = "bc7d7cd957c9ed92288a7c3c96af81fa5291f65247a76a34dac7b6af74e52ba0" dependencies = [ "actix-macros", "futures-core", @@ -97,11 +98,10 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.0.0-beta.3" +version = "2.0.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99198727204a48f82559c18e4b0ba3197b97d5f4576a32bdbef371f3b4599c1" +checksum = "0872f02a1871257ef09c5a269dce5dc5fea5ccf502adbf5d39f118913b61411c" dependencies = [ - "actix-codec", "actix-rt", "actix-service", "actix-utils", @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "actix-tls" -version = "3.0.0-beta.4" +version = "3.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b1455e3f7a26d40cfc1080b571f41e8165e5a88e937ed579f7a4b3d55b0370" +checksum = "65b7bb60840962ef0332f7ea01a57d73a24d2cb663708511ff800250bbfef569" dependencies = [ "actix-codec", "actix-rt", @@ -144,24 +144,19 @@ dependencies = [ [[package]] name = "actix-utils" -version = "3.0.0-beta.2" +version = "3.0.0-beta.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458795e09a29bc5557604f9ff6f32236fd0ee457d631672e4ec8f6a0103bb292" +checksum = "c7e96334417549752384b169ca5d52bcea9e5081dbb2d3933599ac8b770f642a" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "futures-core", - "futures-sink", - "log", + "local-waker", "pin-project-lite", ] [[package]] name = "actix-web" -version = "4.0.0-beta.4" +version = "4.0.0-beta.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d95e50c9e32e8456220b5804867de76e97a86ab8c38b51c9edcccc0f0fddca7" +checksum = "6de19cc341c2e68b1ee126de171e86b610b5bbcecc660d1250ebed73e0257bd6" dependencies = [ "actix-codec", "actix-http", @@ -174,23 +169,23 @@ dependencies = [ "actix-utils", "actix-web-codegen", "ahash 0.7.2", - "awc", "bytes", "derive_more", "either", "encoding_rs", "futures-core", "futures-util", + "language-tags", "log", "mime", + "once_cell", "pin-project", "regex", - "rustls", "serde", "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.3.19", + "socket2", "time 0.2.26", "url", ] @@ -390,33 +385,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "awc" -version = "3.0.0-beta.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09aecd8728f6491a62b27454ea4b36fb7e50faf32928b0369b644e402c651f4e" -dependencies = [ - "actix-codec", - "actix-http", - "actix-rt", - "actix-service", - "base64 0.13.0", - "bytes", - "cfg-if", - "derive_more", - "futures-core", - "itoa", - "log", - "mime", - "percent-encoding", - "pin-project-lite", - "rand", - "rustls", - "serde", - "serde_json", - "serde_urlencoded", -] - [[package]] name = "base-x" version = "0.2.8" @@ -661,9 +629,9 @@ dependencies = [ [[package]] name = "const_fn" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" +checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28" [[package]] name = "convert_case" @@ -1075,9 +1043,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "http" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747" +checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ "bytes", "fnv", @@ -1097,9 +1065,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.3.5" +version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" +checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589" [[package]] name = "httpdate" @@ -1109,9 +1077,9 @@ checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" [[package]] name = "hyper" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7" +checksum = "8bf09f61b52cfcf4c00de50df88ae423d6c02354e385a86341133b5338630ad1" dependencies = [ "bytes", "futures-channel", @@ -1124,7 +1092,7 @@ dependencies = [ "httpdate", "itoa", "pin-project", - "socket2 0.3.19", + "socket2", "tokio", "tower-service", "tracing", @@ -1188,9 +1156,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821" +checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" dependencies = [ "wasm-bindgen", ] @@ -1218,9 +1186,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.91" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" +checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" [[package]] name = "libsodium-sys" @@ -1234,10 +1202,28 @@ dependencies = [ ] [[package]] -name = "lock_api" -version = "0.4.2" +name = "local-channel" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +checksum = "6246c68cf195087205a0512559c97e15eaf95198bf0e206d662092cdcb03fe9f" +dependencies = [ + "futures-core", + "futures-sink", + "futures-util", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f9a2d3e27ce99ce2c3aad0b09b1a7b916293ea9b2bf624c13fe646fadd8da4" + +[[package]] +name = "lock_api" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" dependencies = [ "scopeguard", ] @@ -1277,6 +1263,7 @@ dependencies = [ "futures", "log", "lru", + "once_cell", "parking_lot", "reqwest", "rustls", @@ -1286,6 +1273,7 @@ dependencies = [ "sodiumoxide", "ssri", "thiserror", + "tokio", "url", ] @@ -1374,7 +1362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19900e7eee95eb2b3c2e26d12a874cc80aaf750e31be6fcbe743ead369fa45d" dependencies = [ "libc", - "socket2 0.4.0", + "socket2", ] [[package]] @@ -1616,9 +1604,9 @@ checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -1822,9 +1810,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d493c5f39e02dfb062cd8f33301f90f9b13b650e8c1b1d0fd75c19dd64bff69d" +checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" dependencies = [ "bitflags", "core-foundation", @@ -1835,9 +1823,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee48cdde5ed250b0d3252818f646e174ab414036edb884dde62d80a3ac6082d" +checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339" dependencies = [ "core-foundation-sys", "libc", @@ -1946,9 +1934,9 @@ dependencies = [ [[package]] name = "signal-hook" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aa894ef3fade0ee7243422f4fbbd6c2b48e6de767e621d37ef65f2310f53cea" +checksum = "ef33d6d0cd06e0840fba9985aab098c147e67e05cee14d412d3345ed14ff30ac" dependencies = [ "libc", "signal-hook-registry", @@ -1988,17 +1976,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if", - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.4.0" @@ -2108,9 +2085,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.64" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb" dependencies = [ "proc-macro2", "quote", @@ -2230,9 +2207,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" dependencies = [ "tinyvec_macros", ] @@ -2254,13 +2231,26 @@ dependencies = [ "libc", "memchr", "mio", + "num_cpus", "once_cell", "parking_lot", "pin-project-lite", "signal-hook-registry", + "tokio-macros", "winapi", ] +[[package]] +name = "tokio-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tokio-native-tls" version = "0.3.0" @@ -2336,9 +2326,9 @@ checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" dependencies = [ "matches", ] @@ -2457,9 +2447,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe" +checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" dependencies = [ "cfg-if", "serde", @@ -2469,9 +2459,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3" +checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" dependencies = [ "bumpalo", "lazy_static", @@ -2484,9 +2474,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73157efb9af26fb564bb59a009afd1c7c334a44db171d280690d0c3faaec3468" +checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" dependencies = [ "cfg-if", "js-sys", @@ -2496,9 +2486,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b" +checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2506,9 +2496,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d" +checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ "proc-macro2", "quote", @@ -2519,15 +2509,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.72" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa" +checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" [[package]] name = "web-sys" -version = "0.3.49" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fe19d70f5dacc03f6e46777213facae5ac3801575d56ca6cbd4c93dcd12310" +checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" dependencies = [ "js-sys", "wasm-bindgen", @@ -2545,9 +2535,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ "webpki", ] diff --git a/Cargo.toml b/Cargo.toml index 2fd1f40..e89fdc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,8 +19,9 @@ clap = { version = "3.0.0-beta.2", features = [ "wrap_help" ] } ctrlc = "3" dotenv = "0.15" futures = "0.3" +once_cell = "1" parking_lot = "0.11" -reqwest = { version = "0.11", features = [ "json" ] } +reqwest = { version = "0.11", features = [ "json", "stream" ] } log = "0.4" lru = "0.6" rustls = "0.19" @@ -30,6 +31,7 @@ simple_logger = "1" sodiumoxide = "0.2" ssri = "5" thiserror = "1" +tokio = { version = "1", features = [ "full" ] } url = { version = "2", features = [ "serde" ] } [profile.release] diff --git a/src/fs.rs b/src/fs.rs new file mode 100644 index 0000000..1fc6d81 --- /dev/null +++ b/src/fs.rs @@ -0,0 +1,153 @@ +use std::task::{Context, Poll}; +use std::{collections::HashMap, path::PathBuf}; +use std::{path::Path, sync::atomic::Ordering}; +use std::{pin::Pin, sync::atomic::AtomicU8}; +use std::{sync::Arc, time::Duration}; + +use bytes::{Bytes, BytesMut}; +use futures::{Future, Stream, StreamExt}; +use once_cell::sync::Lazy; +use parking_lot::RwLock; +use reqwest::Error; +use tokio::fs::{remove_file, File, OpenOptions}; +use tokio::io::{AsyncRead, AsyncWriteExt, ReadBuf}; +use tokio::time::Sleep; + +static WRITING_STATUS: Lazy>>> = + Lazy::new(|| RwLock::new(HashMap::new())); + +pub async fn transparent_file_stream( + path: &Path, + mut byte_stream: impl Stream> + Unpin + Send + 'static, +) -> Result>, std::io::Error> { + if let Some(arc) = WRITING_STATUS.read().get(path) { + FromFsStream::new(path, Arc::clone(&arc)).await + } else { + let done_writing_flag = Arc::new(CacheStatus::new()); + + { + let mut write_lock = WRITING_STATUS.write(); + File::create(path).await?; // we need to make sure the file exists and is truncated. + write_lock.insert(path.to_path_buf(), Arc::clone(&done_writing_flag)); + } + + let write_flag = Arc::clone(&done_writing_flag); + // need owned variant because async lifetime + let mut file = OpenOptions::new().write(true).open(path).await?; + let path_buf = path.to_path_buf(); + tokio::spawn(async move { + let path_buf = path_buf; // moves path buf into async + let mut was_errored = false; + while let Some(bytes) = byte_stream.next().await { + match bytes { + Ok(bytes) => file.write_all(&bytes).await?, + Err(_) => was_errored = true, + } + } + + if was_errored { + // It's ok if the deleting the file fails, since we truncate on + // create anyways + let _ = remove_file(&path_buf).await; + } else { + file.flush().await?; + file.sync_all().await?; + } + + let mut write_lock = WRITING_STATUS.write(); + // This needs to be written atomically with the write lock, else + // it's possible we have an inconsistent state + if was_errored { + write_flag.store(WritingStatus::Error); + } else { + write_flag.store(WritingStatus::Done); + } + write_lock.remove(&path_buf); + + // We don't ever check this, so the return value doesn't matter + Ok::<_, std::io::Error>(()) + }); + + FromFsStream::new(path, Arc::clone(&done_writing_flag)).await + } +} + +struct FromFsStream { + file: Pin>, + sleep: Pin>, + is_file_done_writing: Arc, +} + +impl FromFsStream { + async fn new(path: &Path, is_done: Arc) -> Result { + Ok(Self { + file: Box::pin(File::open(path).await?), + // 0.5ms + sleep: Box::pin(tokio::time::sleep(Duration::from_micros(500))), + is_file_done_writing: is_done, + }) + } +} + +/// Represents some upstream error. +struct UpstreamError; + +impl Stream for FromFsStream { + type Item = Result; + + fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let status = self.is_file_done_writing.load(); + + let mut bytes = BytesMut::with_capacity(1460); + let mut buffer = ReadBuf::new(&mut bytes); + let polled_result = self.file.as_mut().poll_read(cx, &mut buffer); + + match (status, buffer.filled().len()) { + // Prematurely reached EOF, schedule a poll in the future + (WritingStatus::NotDone, 0) => { + let _ = self.sleep.as_mut().poll(cx); + Poll::Pending + } + // We got an error, abort the read. + (WritingStatus::Error, _) => Poll::Ready(Some(Err(UpstreamError))), + _ => polled_result.map(|_| Some(Ok(bytes.split().into()))), + } + } +} + +struct CacheStatus(AtomicU8); + +impl CacheStatus { + #[inline] + fn new() -> Self { + Self(AtomicU8::new(WritingStatus::NotDone as u8)) + } + + #[inline] + fn store(&self, status: WritingStatus) { + self.0.store(status as u8, Ordering::Release); + } + + #[inline] + fn load(&self) -> WritingStatus { + self.0.load(Ordering::Acquire).into() + } +} + +enum WritingStatus { + NotDone = 0, + Done, + Error, +} + +impl From for WritingStatus { + #[inline] + fn from(v: u8) -> Self { + match v { + 0 => Self::NotDone, + 1 => Self::Done, + 2 => Self::Error, + _ => unreachable!(), + } + } +} diff --git a/src/main.rs b/src/main.rs index ad901a9..279282d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,6 +25,7 @@ use thiserror::Error; mod cache; mod config; +mod fs; mod ping; mod routes; mod state; diff --git a/src/routes.rs b/src/routes.rs index 4f7dc71..7382431 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -285,5 +285,5 @@ fn construct_response(cached: &CachedImage) -> ServerResponse { resp.append_header((LAST_MODIFIED, &**last_modified)); } - return ServerResponse::HttpResponse(push_headers(&mut resp).streaming(stream::iter(data))); + ServerResponse::HttpResponse(push_headers(&mut resp).streaming(stream::iter(data))) }