Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3363631
D8892.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
23 KB
Referenced Files
None
Subscribers
None
D8892.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Tue, Nov 26, 2:47 AM (15 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2582169
Default Alt Text
D8892.diff (23 KB)
Attached To
Mode
D8892: [services] Extract multipart handling logic to lib
Attached
Detach File
Event Timeline
Log In to Comment