aboutsummaryrefslogtreecommitdiff
path: root/src/k2v-client
diff options
context:
space:
mode:
Diffstat (limited to 'src/k2v-client')
-rw-r--r--src/k2v-client/Cargo.toml5
-rw-r--r--src/k2v-client/bin/k2v-cli.rs (renamed from src/k2v-client/src/bin/k2v-cli.rs)0
-rw-r--r--src/k2v-client/error.rs (renamed from src/k2v-client/src/error.rs)7
-rw-r--r--src/k2v-client/lib.rs (renamed from src/k2v-client/src/lib.rs)53
4 files changed, 61 insertions, 4 deletions
diff --git a/src/k2v-client/Cargo.toml b/src/k2v-client/Cargo.toml
index 84c6b8b2..224414ab 100644
--- a/src/k2v-client/Cargo.toml
+++ b/src/k2v-client/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
base64 = "0.13.0"
http = "0.2.6"
+log = "0.4"
rusoto_core = "0.48.0"
rusoto_credential = "0.48.0"
rusoto_signature = "0.48.0"
@@ -22,6 +23,10 @@ garage_util = { path = "../util", optional = true }
[features]
cli = ["clap", "tokio/fs", "tokio/io-std", "garage_util"]
+[lib]
+path = "lib.rs"
+
[[bin]]
name = "k2v-cli"
+path = "bin/k2v-cli.rs"
required-features = ["cli"]
diff --git a/src/k2v-client/src/bin/k2v-cli.rs b/src/k2v-client/bin/k2v-cli.rs
index 38c39361..38c39361 100644
--- a/src/k2v-client/src/bin/k2v-cli.rs
+++ b/src/k2v-client/bin/k2v-cli.rs
diff --git a/src/k2v-client/src/error.rs b/src/k2v-client/error.rs
index 62357934..37c221f2 100644
--- a/src/k2v-client/src/error.rs
+++ b/src/k2v-client/error.rs
@@ -5,6 +5,13 @@ use thiserror::Error;
/// Errors returned by this crate
#[derive(Error, Debug)]
pub enum Error {
+ #[error("{0}, {1}: {2} (path = {3})")]
+ Remote(
+ http::StatusCode,
+ Cow<'static, str>,
+ Cow<'static, str>,
+ Cow<'static, str>,
+ ),
#[error("received invalid response: {0}")]
InvalidResponse(Cow<'static, str>),
#[error("not found")]
diff --git a/src/k2v-client/src/lib.rs b/src/k2v-client/lib.rs
index ba1cd6ea..95974d7a 100644
--- a/src/k2v-client/src/lib.rs
+++ b/src/k2v-client/lib.rs
@@ -4,6 +4,7 @@ use std::time::Duration;
use http::header::{ACCEPT, CONTENT_LENGTH, CONTENT_TYPE};
use http::status::StatusCode;
use http::HeaderMap;
+use log::{debug, error};
use rusoto_core::{ByteStream, DispatchSignedRequest, HttpClient};
use rusoto_credential::AwsCredentials;
@@ -310,12 +311,47 @@ impl K2vClient {
StatusCode::NO_CONTENT => Vec::new(),
StatusCode::NOT_FOUND => return Err(Error::NotFound),
StatusCode::NOT_MODIFIED => Vec::new(),
- _ => {
- return Err(Error::InvalidResponse(
- format!("invalid error code: {}", res.status).into(),
- ))
+ s => {
+ let err_body = read_body(&mut res.headers, res.body)
+ .await
+ .unwrap_or_default();
+ let err_body_str = std::str::from_utf8(&err_body)
+ .map(String::from)
+ .unwrap_or_else(|_| base64::encode(&err_body));
+
+ if s.is_client_error() || s.is_server_error() {
+ error!("Error response {}: {}", res.status, err_body_str);
+ let err = match serde_json::from_slice::<ErrorResponse>(&err_body) {
+ Ok(err) => Error::Remote(
+ res.status,
+ err.code.into(),
+ err.message.into(),
+ err.path.into(),
+ ),
+ Err(_) => Error::Remote(
+ res.status,
+ "unknown".into(),
+ err_body_str.into(),
+ "?".into(),
+ ),
+ };
+ return Err(err);
+ } else {
+ let msg = format!(
+ "Unexpected response code {}. Response body: {}",
+ res.status, err_body_str
+ );
+ error!("{}", msg);
+ return Err(Error::InvalidResponse(msg.into()));
+ }
}
};
+ debug!(
+ "Response body: {}",
+ std::str::from_utf8(&body)
+ .map(String::from)
+ .unwrap_or_else(|_| base64::encode(&body))
+ );
Ok(Response {
body,
@@ -558,6 +594,15 @@ struct BatchDeleteResponse<'a> {
deleted_items: u64,
}
+#[derive(Deserialize)]
+struct ErrorResponse {
+ code: String,
+ message: String,
+ #[allow(dead_code)]
+ region: String,
+ path: String,
+}
+
struct Response {
body: Vec<u8>,
status: StatusCode,