aboutsummaryrefslogtreecommitdiff
path: root/src/k2v-client
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2024-02-13 11:24:56 +0100
committerAlex Auvolat <alex@adnab.me>2024-02-13 11:36:28 +0100
commitcf2af186fcc0c8f581a966454b6cd4720d3821f0 (patch)
tree37a978ba9ffb780fc828cff7b8ec93662d50884f /src/k2v-client
parentdb48dd3d6c1f9e86a62e9b8edfce2c1620bcd5f3 (diff)
parent823078b4cdaf93e09de0847c5eaa75beb7b26b7f (diff)
downloadgarage-cf2af186fcc0c8f581a966454b6cd4720d3821f0.tar.gz
garage-cf2af186fcc0c8f581a966454b6cd4720d3821f0.zip
Merge branch 'main' into next-0.10
Diffstat (limited to 'src/k2v-client')
-rw-r--r--src/k2v-client/Cargo.toml35
-rw-r--r--src/k2v-client/error.rs4
-rw-r--r--src/k2v-client/lib.rs60
3 files changed, 67 insertions, 32 deletions
diff --git a/src/k2v-client/Cargo.toml b/src/k2v-client/Cargo.toml
index 2ccb9fe5..694be1f8 100644
--- a/src/k2v-client/Cargo.toml
+++ b/src/k2v-client/Cargo.toml
@@ -9,25 +9,28 @@ repository = "https://git.deuxfleurs.fr/Deuxfleurs/garage"
readme = "../../README.md"
[dependencies]
-base64 = "0.21"
-sha2 = "0.10"
-hex = "0.4"
-http = "0.2"
-log = "0.4"
-aws-sigv4 = "0.55"
-percent-encoding = "2.2"
-hyper = { version = "0.14", default-features = false, features = ["client", "http1", "http2"] }
-hyper-rustls = { version = "0.24", features = ["http2"] }
-serde = { version = "1.0", features = [ "derive" ] }
-serde_json = "1.0"
-thiserror = "1.0"
-tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
+base64.workspace = true
+sha2.workspace = true
+hex.workspace = true
+http.workspace = true
+http-body-util.workspace = true
+log.workspace = true
+aws-sigv4.workspace = true
+aws-sdk-config.workspace = true
+percent-encoding.workspace = true
+hyper = { workspace = true, default-features = false, features = ["http1", "http2"] }
+hyper-util.workspace = true
+hyper-rustls.workspace = true
+serde.workspace = true
+serde_json.workspace = true
+thiserror.workspace = true
+tokio.workspace = true
# cli deps
-clap = { version = "4.1", optional = true, features = ["derive", "env"] }
+clap = { workspace = true, optional = true }
format_table = { workspace = true, optional = true }
-tracing = { version = "0.1", optional = true }
-tracing-subscriber = { version = "0.3", optional = true, features = ["env-filter"] }
+tracing = { workspace = true, optional = true }
+tracing-subscriber = { workspace = true, optional = true }
[features]
diff --git a/src/k2v-client/error.rs b/src/k2v-client/error.rs
index 564ce497..96f5674a 100644
--- a/src/k2v-client/error.rs
+++ b/src/k2v-client/error.rs
@@ -22,12 +22,14 @@ pub enum Error {
Http(#[from] http::Error),
#[error("hyper error: {0}")]
Hyper(#[from] hyper::Error),
+ #[error("hyper client error: {0}")]
+ HyperClient(#[from] hyper_util::client::legacy::Error),
#[error("invalid header: {0}")]
Header(#[from] hyper::header::ToStrError),
#[error("deserialization error: {0}")]
Deserialization(#[from] serde_json::Error),
#[error("invalid signature parameters: {0}")]
- SignParameters(#[from] aws_sigv4::signing_params::BuildError),
+ SignParameters(#[from] aws_sigv4::sign::v4::signing_params::BuildError),
#[error("could not sign request: {0}")]
SignRequest(#[from] aws_sigv4::http_request::SigningError),
#[error("request timed out")]
diff --git a/src/k2v-client/lib.rs b/src/k2v-client/lib.rs
index 4aa7a20a..852274a7 100644
--- a/src/k2v-client/lib.rs
+++ b/src/k2v-client/lib.rs
@@ -9,11 +9,15 @@ use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
use http::header::{ACCEPT, CONTENT_TYPE};
use http::status::StatusCode;
use http::{HeaderName, HeaderValue, Request};
-use hyper::{body::Bytes, Body};
-use hyper::{client::connect::HttpConnector, Client as HttpClient};
+use http_body_util::{BodyExt, Full as FullBody};
+use hyper::body::Bytes;
use hyper_rustls::HttpsConnector;
+use hyper_util::client::legacy::{connect::HttpConnector, Client as HttpClient};
+use hyper_util::rt::TokioExecutor;
-use aws_sigv4::http_request::{sign, SignableRequest, SigningParams, SigningSettings};
+use aws_sdk_config::config::Credentials;
+use aws_sigv4::http_request::{sign, SignableBody, SignableRequest, SigningSettings};
+use aws_sigv4::sign::v4::SigningParams;
use serde::de::Error as DeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@@ -22,6 +26,8 @@ mod error;
pub use error::Error;
+pub type Body = FullBody<Bytes>;
+
const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
const DEFAULT_POLL_TIMEOUT: Duration = Duration::from_secs(300);
const SERVICE: &str = "k2v";
@@ -53,19 +59,19 @@ pub struct K2vClientConfig {
pub struct K2vClient {
config: K2vClientConfig,
user_agent: HeaderValue,
- client: HttpClient<HttpsConnector<HttpConnector>>,
+ client: HttpClient<HttpsConnector<HttpConnector>, Body>,
}
impl K2vClient {
/// Create a new K2V client.
pub fn new(config: K2vClientConfig) -> Result<Self, Error> {
let connector = hyper_rustls::HttpsConnectorBuilder::new()
- .with_native_roots()
+ .with_native_roots()?
.https_or_http()
.enable_http1()
.enable_http2()
.build();
- let client = HttpClient::builder().build(connector);
+ let client = HttpClient::builder(TokioExecutor::new()).build(connector);
let user_agent: std::borrow::Cow<str> = match &config.user_agent {
Some(ua) => ua.into(),
None => format!("k2v/{}", env!("CARGO_PKG_VERSION")).into(),
@@ -363,21 +369,37 @@ impl K2vClient {
// Sign request
let signing_settings = SigningSettings::default();
+ let identity = Credentials::new(
+ &self.config.aws_access_key_id,
+ &self.config.aws_secret_access_key,
+ None,
+ None,
+ "k2v-client",
+ )
+ .into();
let signing_params = SigningParams::builder()
- .access_key(&self.config.aws_access_key_id)
- .secret_key(&self.config.aws_secret_access_key)
+ .identity(&identity)
.region(&self.config.region)
- .service_name(SERVICE)
+ .name(SERVICE)
.time(SystemTime::now())
.settings(signing_settings)
- .build()?;
+ .build()?
+ .into();
// Convert the HTTP request into a signable request
- let signable_request = SignableRequest::from(&req);
+ let signable_request = SignableRequest::new(
+ req.method().as_str(),
+ req.uri().to_string(),
+ // TODO: get rid of Unwrap
+ req.headers()
+ .iter()
+ .map(|(x, y)| (x.as_str(), y.to_str().unwrap())),
+ SignableBody::Bytes(req.body().as_ref()),
+ )?;
// Sign and then apply the signature to the request
let (signing_instructions, _signature) =
sign(signable_request, &signing_params)?.into_parts();
- signing_instructions.apply_to_request(&mut req);
+ signing_instructions.apply_to_request_http1x(&mut req);
// Send and wait for timeout
let res = tokio::select! {
@@ -398,12 +420,16 @@ impl K2vClient {
};
let body = match res.status {
- StatusCode::OK => hyper::body::to_bytes(body).await?,
+ StatusCode::OK => BodyExt::collect(body).await?.to_bytes(),
StatusCode::NO_CONTENT => Bytes::new(),
StatusCode::NOT_FOUND => return Err(Error::NotFound),
StatusCode::NOT_MODIFIED => Bytes::new(),
s => {
- let err_body = hyper::body::to_bytes(body).await.unwrap_or_default();
+ let err_body = body
+ .collect()
+ .await
+ .map(|x| x.to_bytes())
+ .unwrap_or_default();
let err_body_str = std::str::from_utf8(&err_body)
.map(String::from)
.unwrap_or_else(|_| BASE64_STANDARD.encode(&err_body));
@@ -451,7 +477,11 @@ impl K2vClient {
}
fn build_url<V: AsRef<str>>(&self, partition_key: Option<&str>, query: &[(&str, V)]) -> String {
- let mut url = format!("{}/{}", self.config.endpoint, self.config.bucket);
+ let mut url = format!(
+ "{}/{}",
+ self.config.endpoint.trim_end_matches('/'),
+ self.config.bucket
+ );
if let Some(pk) = partition_key {
url.push('/');
url.extend(utf8_percent_encode(pk, &PATH_ENCODE_SET));