Page MenuHomePhabricator

D8892.id30326.diff
No OneTemporary

D8892.id30326.diff

diff --git a/services/backup/Cargo.lock b/services/backup/Cargo.lock
--- a/services/backup/Cargo.lock
+++ b/services/backup/Cargo.lock
@@ -83,6 +83,44 @@
"syn 2.0.29",
]
+[[package]]
+name = "actix-multipart"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee489e3c01eae4d1c35b03c4493f71cb40d93f66b14558feb1b1a807671cc4e"
+dependencies = [
+ "actix-multipart-derive",
+ "actix-utils",
+ "actix-web",
+ "bytes",
+ "derive_more",
+ "futures-core",
+ "futures-util",
+ "httparse",
+ "local-waker",
+ "log",
+ "memchr",
+ "mime",
+ "serde",
+ "serde_json",
+ "serde_plain",
+ "tempfile",
+ "tokio",
+]
+
+[[package]]
+name = "actix-multipart-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ec592f234db8a253cf80531246a4407c8a70530423eea80688a6c5a44a110e7"
+dependencies = [
+ "darling",
+ "parse-size",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "actix-router"
version = "0.5.1"
@@ -888,6 +926,9 @@
version = "0.1.0"
dependencies = [
"actix-cors",
+ "actix-multipart",
+ "actix-web",
+ "anyhow",
"aws-config",
"aws-sdk-dynamodb",
"aws-types",
@@ -895,10 +936,12 @@
"derive_more",
"futures-core",
"futures-util",
+ "http",
"reqwest",
"serde",
"serde_json",
"tokio",
+ "tokio-stream",
"tracing",
]
@@ -963,6 +1006,41 @@
"typenum",
]
+[[package]]
+name = "darling"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "deranged"
version = "0.3.8"
@@ -1379,6 +1457,12 @@
"cc",
]
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
[[package]]
name = "idna"
version = "0.4.0"
@@ -1724,6 +1808,12 @@
"windows-targets",
]
+[[package]]
+name = "parse-size"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae"
+
[[package]]
name = "paste"
version = "1.0.14"
@@ -2162,6 +2252,15 @@
"serde",
]
+[[package]]
+name = "serde_plain"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
diff --git a/services/blob/Cargo.lock b/services/blob/Cargo.lock
--- a/services/blob/Cargo.lock
+++ b/services/blob/Cargo.lock
@@ -976,11 +976,18 @@
version = "0.1.0"
dependencies = [
"actix-cors",
+ "actix-multipart",
+ "actix-web",
+ "anyhow",
"aws-config",
"aws-sdk-dynamodb",
"aws-types",
"chrono",
"derive_more",
+ "futures-core",
+ "futures-util",
+ "http",
+ "tokio-stream",
"tracing",
]
diff --git a/services/blob/src/http/handlers/blob.rs b/services/blob/src/http/handlers/blob.rs
--- a/services/blob/src/http/handlers/blob.rs
+++ b/services/blob/src/http/handlers/blob.rs
@@ -2,18 +2,16 @@
use crate::service::BlobService;
use crate::validate_identifier;
-use actix_web::error::{
- ErrorBadRequest, ErrorInternalServerError, ErrorRangeNotSatisfiable,
-};
+use actix_web::error::{ErrorBadRequest, ErrorRangeNotSatisfiable};
use actix_web::{
http::header::{ByteRangeSpec, Range},
- web, Error as HttpError, HttpResponse,
+ web, HttpResponse,
};
-use anyhow::Result;
use async_stream::try_stream;
+use comm_services_lib::http::multipart;
use serde::{Deserialize, Serialize};
use tokio_stream::StreamExt;
-use tracing::{debug, info, instrument, trace, warn};
+use tracing::{info, instrument, trace, warn};
use tracing_futures::Instrument;
/// Returns a tuple of first and last byte number (inclusive) represented by given range header.
@@ -137,31 +135,6 @@
Ok(HttpResponse::Ok().json(web::Json(AssignHolderResponnse { data_exists })))
}
-async fn get_blob_hash_field(
- multipart_payload: &mut actix_multipart::Multipart,
-) -> Result<String, HttpError> {
- let Some(mut field) = multipart_payload.try_next().await? else {
- debug!("Malfolmed multipart request");
- return Err(ErrorBadRequest("Bad request"));
- };
-
- if field.name() != "blob_hash" {
- warn!("Blob hash is required as a first form field");
- return Err(ErrorBadRequest("Bad request"));
- }
-
- let mut buf = Vec::new();
- while let Some(chunk) = field.try_next().await? {
- buf.extend_from_slice(&chunk);
- }
-
- let blob_hash = String::from_utf8(buf)
- .map_err(|_| ErrorInternalServerError("Internal error"))?;
-
- validate_identifier!(blob_hash);
- return Ok(blob_hash);
-}
-
#[instrument(skip_all, name = "upload_blob", fields(blob_hash))]
pub async fn upload_blob_handler(
service: web::Data<BlobService>,
@@ -169,13 +142,22 @@
) -> actix_web::Result<HttpResponse> {
info!("Upload blob request");
- let blob_hash = get_blob_hash_field(&mut payload).await?;
- debug!("Received blob_hash: {}", &blob_hash);
+ let Some((name, blob_hash)) = multipart::get_text_field(&mut payload).await? else {
+ warn!("Malformed request: expected a field.");
+ return Err(ErrorBadRequest("Bad request"));
+ };
+
+ if name != "blob_hash" {
+ warn!(name, "Malformed request: 'blob_hash' text field expected.");
+ return Err(ErrorBadRequest("Bad request"));
+ }
+ validate_identifier!(blob_hash);
+
tracing::Span::current().record("blob_hash", &blob_hash);
trace!("Receiving blob data");
let stream = try_stream! {
- while let Some(mut field) = payload.try_next().await.map_err(Box::new)? {
+ while let Some(mut field) = payload.try_next().await? {
let field_name = field.name();
if field_name != "blob_data" {
warn!(
@@ -185,8 +167,8 @@
Err(ErrorBadRequest("Bad request"))?;
}
- while let Some(chunk) = field.try_next().await.map_err(Box::new)? {
- yield chunk.to_vec();
+ while let Some(chunk) = field.try_next().await? {
+ yield chunk;
}
}
trace!("Stream done");
diff --git a/services/blob/src/service.rs b/services/blob/src/service.rs
--- a/services/blob/src/service.rs
+++ b/services/blob/src/service.rs
@@ -4,6 +4,8 @@
use async_stream::try_stream;
use chrono::Duration;
+use comm_services_lib::http::ByteStream;
+use comm_services_lib::tools::BoxedError;
use tokio_stream::StreamExt;
use tonic::codegen::futures_core::Stream;
use tracing::{debug, error, trace, warn};
@@ -14,7 +16,7 @@
};
use crate::database::DBError;
use crate::s3::{Error as S3Error, S3Client, S3Path};
-use crate::tools::{BoxedError, ByteStream, MemOps};
+use crate::tools::MemOps;
use crate::{constants::BLOB_DOWNLOAD_CHUNK_SIZE, database::DatabaseClient};
#[derive(
@@ -132,13 +134,13 @@
tokio::pin!(blob_data_stream);
let mut s3_chunk: Vec<u8> = Vec::new();
- while let Some(mut chunk) =
+ while let Some(chunk) =
blob_data_stream.try_next().await.map_err(|err| {
warn!("Failed to get data chunk: {:?}", err);
BlobServiceError::InputError(err)
})?
{
- s3_chunk.append(&mut chunk);
+ s3_chunk.extend_from_slice(&chunk);
// New parts should be added to AWS only if they exceed minimum part size,
// Otherwise AWS returns error
diff --git a/services/blob/src/tools.rs b/services/blob/src/tools.rs
--- a/services/blob/src/tools.rs
+++ b/services/blob/src/tools.rs
@@ -1,17 +1,3 @@
-use std::error::Error as StdError;
-use tonic::codegen::futures_core::Stream;
-
-pub type BoxedError = Box<dyn StdError>;
-// Trait type aliases aren't supported in Rust, but
-// we can workaround this by creating an empty trait
-// that extends the traits we want to alias.
-#[rustfmt::skip]
-pub trait ByteStream:
- Stream<Item = Result<Vec<u8>, BoxedError>> {}
-#[rustfmt::skip]
-impl<T> ByteStream for T where
- T: Stream<Item = Result<Vec<u8>, BoxedError>> {}
-
pub trait MemOps {
fn take_out(&mut self) -> Self;
}
diff --git a/services/comm-services-lib/Cargo.lock b/services/comm-services-lib/Cargo.lock
--- a/services/comm-services-lib/Cargo.lock
+++ b/services/comm-services-lib/Cargo.lock
@@ -47,10 +47,12 @@
"ahash 0.8.3",
"base64",
"bitflags",
+ "brotli",
"bytes",
"bytestring",
"derive_more",
"encoding_rs",
+ "flate2",
"futures-core",
"h2",
"http",
@@ -68,6 +70,55 @@
"tokio",
"tokio-util",
"tracing",
+ "zstd",
+]
+
+[[package]]
+name = "actix-macros"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
+dependencies = [
+ "quote",
+ "syn 2.0.29",
+]
+
+[[package]]
+name = "actix-multipart"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dee489e3c01eae4d1c35b03c4493f71cb40d93f66b14558feb1b1a807671cc4e"
+dependencies = [
+ "actix-multipart-derive",
+ "actix-utils",
+ "actix-web",
+ "bytes",
+ "derive_more",
+ "futures-core",
+ "futures-util",
+ "httparse",
+ "local-waker",
+ "log",
+ "memchr",
+ "mime",
+ "serde",
+ "serde_json",
+ "serde_plain",
+ "tempfile",
+ "tokio",
+]
+
+[[package]]
+name = "actix-multipart-derive"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ec592f234db8a253cf80531246a4407c8a70530423eea80688a6c5a44a110e7"
+dependencies = [
+ "darling",
+ "parse-size",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
]
[[package]]
@@ -140,15 +191,18 @@
dependencies = [
"actix-codec",
"actix-http",
+ "actix-macros",
"actix-router",
"actix-rt",
"actix-server",
"actix-service",
"actix-utils",
+ "actix-web-codegen",
"ahash 0.7.6",
"bytes",
"bytestring",
"cfg-if",
+ "cookie",
"derive_more",
"encoding_rs",
"futures-core",
@@ -170,6 +224,18 @@
"url",
]
+[[package]]
+name = "actix-web-codegen"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9"
+dependencies = [
+ "actix-router",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "addr2line"
version = "0.21.0"
@@ -217,6 +283,21 @@
"memchr",
]
+[[package]]
+name = "alloc-no-stdlib"
+version = "2.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
+
+[[package]]
+name = "alloc-stdlib"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
+dependencies = [
+ "alloc-no-stdlib",
+]
+
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -226,6 +307,12 @@
"libc",
]
+[[package]]
+name = "anyhow"
+version = "1.0.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -596,6 +683,27 @@
"generic-array",
]
+[[package]]
+name = "brotli"
+version = "3.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+ "brotli-decompressor",
+]
+
+[[package]]
+name = "brotli-decompressor"
+version = "2.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+]
+
[[package]]
name = "bumpalo"
version = "3.12.0"
@@ -632,6 +740,9 @@
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+dependencies = [
+ "jobserver",
+]
[[package]]
name = "cfg-if"
@@ -669,6 +780,9 @@
version = "0.1.0"
dependencies = [
"actix-cors",
+ "actix-multipart",
+ "actix-web",
+ "anyhow",
"aws-config",
"aws-sdk-dynamodb",
"aws-types",
@@ -676,10 +790,12 @@
"derive_more",
"futures-core",
"futures-util",
+ "http",
"reqwest",
"serde",
"serde_json",
"tokio",
+ "tokio-stream",
"tracing",
]
@@ -689,6 +805,17 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+[[package]]
+name = "cookie"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
+dependencies = [
+ "percent-encoding",
+ "time 0.3.20",
+ "version_check",
+]
+
[[package]]
name = "core-foundation"
version = "0.9.3"
@@ -714,6 +841,15 @@
"libc",
]
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
[[package]]
name = "crypto-common"
version = "0.1.6"
@@ -748,7 +884,7 @@
"proc-macro2",
"quote",
"scratch",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -765,7 +901,42 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.14.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 1.0.109",
]
[[package]]
@@ -778,7 +949,7 @@
"proc-macro2",
"quote",
"rustc_version",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -837,6 +1008,16 @@
"instant",
]
+[[package]]
+name = "flate2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
[[package]]
name = "fnv"
version = "1.0.7"
@@ -896,7 +1077,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -1111,6 +1292,12 @@
"cxx-build",
]
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
[[package]]
name = "idna"
version = "0.3.0"
@@ -1163,6 +1350,15 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
+[[package]]
+name = "jobserver"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "js-sys"
version = "0.3.61"
@@ -1370,7 +1566,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -1420,6 +1616,12 @@
"windows-targets 0.48.1",
]
+[[package]]
+name = "parse-size"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae"
+
[[package]]
name = "paste"
version = "1.0.14"
@@ -1449,7 +1651,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -1750,7 +1952,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -1764,6 +1966,15 @@
"serde",
]
+[[package]]
+name = "serde_plain"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6018081315db179d0ce57b1fe4b62a12a0028c9cf9bbef868c9cf477b3c34ae"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@@ -1848,6 +2059,12 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
[[package]]
name = "subtle"
version = "2.4.1"
@@ -1865,6 +2082,17 @@
"unicode-ident",
]
+[[package]]
+name = "syn"
+version = "2.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
[[package]]
name = "tempfile"
version = "3.5.0"
@@ -1980,9 +2208,9 @@
[[package]]
name = "tokio-stream"
-version = "0.1.12"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313"
+checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
dependencies = [
"futures-core",
"pin-project-lite",
@@ -2052,7 +2280,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
@@ -2196,7 +2424,7 @@
"once_cell",
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
"wasm-bindgen-shared",
]
@@ -2230,7 +2458,7 @@
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -2472,3 +2700,33 @@
version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"
+
+[[package]]
+name = "zstd"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "6.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
+dependencies = [
+ "libc",
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.8+zstd.1.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
diff --git a/services/comm-services-lib/Cargo.toml b/services/comm-services-lib/Cargo.toml
--- a/services/comm-services-lib/Cargo.toml
+++ b/services/comm-services-lib/Cargo.toml
@@ -13,7 +13,15 @@
"dep:serde_json",
"dep:tokio",
]
-http = ["dep:actix-cors"]
+http = [
+ "dep:actix-cors",
+ "dep:actix-web",
+ "dep:actix-multipart",
+ "dep:futures-core",
+ "dep:futures-util",
+ "dep:http",
+ "dep:tokio-stream",
+]
[dependencies]
aws-config = "0.55"
@@ -22,6 +30,7 @@
chrono = "0.4"
derive_more = "0.99"
tracing = "0.1"
+anyhow = "1.0.74"
# blob client dependencies
futures-core = { version = "0.3", optional = true }
futures-util = { version = "0.3", optional = true }
@@ -35,3 +44,7 @@
tokio = { version = "1.32", optional = true }
# http dependencies
actix-cors = { version = "0.6", optional = true }
+actix-web = { version = "4.3", optional = true }
+http = { version = "0.2.9", optional = true }
+actix-multipart = { version = "0.6", optional = true }
+tokio-stream = { version = "0.1.14", optional = true }
diff --git a/services/comm-services-lib/src/http.rs b/services/comm-services-lib/src/http.rs
--- a/services/comm-services-lib/src/http.rs
+++ b/services/comm-services-lib/src/http.rs
@@ -1,4 +1,9 @@
+pub mod multipart;
+
+use crate::tools::BoxedError;
use actix_cors::Cors;
+use actix_web::web::Bytes;
+use futures_core::Stream;
pub fn cors_config(is_sandbox: bool) -> Cors {
// For local development, use relaxed CORS config
@@ -16,3 +21,13 @@
.allow_any_header()
.expose_any_header()
}
+
+// Trait type aliases aren't supported in Rust, but
+// we can workaround this by creating an empty trait
+// that extends the traits we want to alias.
+#[rustfmt::skip]
+pub trait ByteStream:
+ Stream<Item = Result<Bytes, BoxedError>> {}
+#[rustfmt::skip]
+impl<T> ByteStream for T where
+ T: Stream<Item = Result<Bytes, BoxedError>> {}
diff --git a/services/comm-services-lib/src/http/multipart.rs b/services/comm-services-lib/src/http/multipart.rs
new file mode 100644
--- /dev/null
+++ b/services/comm-services-lib/src/http/multipart.rs
@@ -0,0 +1,42 @@
+use actix_multipart::{Field, MultipartError};
+use actix_web::error::ParseError;
+use tokio_stream::StreamExt;
+
+/// Can be used to get a single field from multipart body with it's data
+/// converted to a string
+///
+/// # Example
+/// ```no_run
+/// # use comm_services_lib::http::multipart;
+/// # use actix_multipart::Multipart;
+/// # async fn f(mut payload: Multipart) {
+/// let Some((name, mut stream)) = multipart::get_text_field(&mut payload).await.unwrap() else {
+/// // Missing field
+/// return;
+/// };
+/// if name != "Field name" {
+/// // Wrong field name
+/// return;
+/// };
+/// println!("Got string: {name}");
+/// # }
+/// ```
+pub async fn get_text_field(
+ multipart: &mut actix_multipart::Multipart,
+) -> anyhow::Result<Option<(String, String)>, MultipartError> {
+ let Some(mut field): Option<Field> = multipart.try_next().await? else {
+ return Ok(None);
+ };
+
+ let name = field.name().to_string();
+
+ let mut buf = Vec::new();
+ while let Some(chunk) = field.try_next().await? {
+ buf.extend_from_slice(&chunk);
+ }
+
+ let text =
+ String::from_utf8(buf).map_err(|err| ParseError::Utf8(err.utf8_error()))?;
+
+ Ok(Some((name, text)))
+}
diff --git a/services/comm-services-lib/src/tools.rs b/services/comm-services-lib/src/tools.rs
--- a/services/comm-services-lib/src/tools.rs
+++ b/services/comm-services-lib/src/tools.rs
@@ -18,6 +18,8 @@
.all(|c| c.is_ascii_alphanumeric() || VALID_IDENTIFIER_CHARS.contains(&c))
}
+pub type BoxedError = Box<dyn std::error::Error>;
+
#[cfg(test)]
mod valid_identifier_tests {
use super::*;
diff --git a/services/feature-flags/Cargo.lock b/services/feature-flags/Cargo.lock
--- a/services/feature-flags/Cargo.lock
+++ b/services/feature-flags/Cargo.lock
@@ -235,9 +235,9 @@
[[package]]
name = "anyhow"
-version = "1.0.69"
+version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]]
name = "autocfg"
@@ -727,6 +727,7 @@
name = "comm-services-lib"
version = "0.1.0"
dependencies = [
+ "anyhow",
"aws-config",
"aws-sdk-dynamodb",
"aws-types",

File Metadata

Mime Type
text/plain
Expires
Sat, Sep 28, 11:58 PM (6 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2198328
Default Alt Text
D8892.id30326.diff (23 KB)

Event Timeline