Skip to content

Commit

Permalink
Deserialize from bytes, add json_data_content feature
Browse files Browse the repository at this point in the history
  • Loading branch information
fussybeaver committed Jun 18, 2022
1 parent 06af7c9 commit 4633cb1
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 20 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Expand Up @@ -18,6 +18,8 @@ test_http = []
test_ssl = ["ssl"]
# Enable tests specifically for macos
test_macos = []
# Enable JSON payload in deserialization errors
json_data_content = []
# Enable rustls / ssl
ssl = ["dirs-next", "hyper-rustls", "rustls", "rustls-native-certs", "rustls-pemfile", "webpki", "webpki-roots"]
ct_logs = ["ssl", "ct-logs"]
Expand Down
47 changes: 31 additions & 16 deletions src/docker.rs
@@ -1,6 +1,4 @@
use std::cmp;
use std::env;
use std::fmt;
use std::{fmt, cmp, env};
#[cfg(feature = "ssl")]
use std::fs;
use std::future::Future;
Expand Down Expand Up @@ -57,6 +55,9 @@ pub const DEFAULT_DOCKER_HOST: &str = "tcp://localhost:2375";
/// Default timeout for all requests is 2 minutes.
const DEFAULT_TIMEOUT: u64 = 120;

/// Maximum response payload size (16M)
const MAX_ALLOWED_RESPONSE_SIZE: usize = 16777216;

/// Default Client Version to communicate with the server.
pub const API_DEFAULT_VERSION: &ClientVersion = &ClientVersion {
major_version: 1,
Expand Down Expand Up @@ -1145,19 +1146,33 @@ impl Docker {
where
T: DeserializeOwned,
{
let contents = Docker::decode_into_string(response).await?;

debug!("Decoded into string: {}", &contents);
serde_json::from_str::<T>(&contents).map_err(|e| {
if e.is_data() {
JsonDataError {
message: e.to_string(),
column: e.column(),
contents: contents.to_owned(),
// Protect against malicious response
let response_content_length = match response.body().size_hint().1 {
Some(size) => size,
None => MAX_ALLOWED_RESPONSE_SIZE + 1,
};

if response_content_length < MAX_ALLOWED_RESPONSE_SIZE {
let bytes = hyper::body::to_bytes(response.into_body()).await?;

debug!("Decoded into string: {}", &String::from_utf8_lossy(&bytes));

serde_json::from_slice::<T>(&bytes).map_err(|e| {
if e.is_data() {
JsonDataError {
message: e.to_string(),
column: e.column(),
#[cfg(feature = "json_data_content")]
contents: String::from_utf8_lossy(&bytes).to_string(),
}
} else {
e.into()
}
} else {
e.into()
}
})
})

} else {
Err(OversizedResponsePayloadError { payload_size: response_content_length as u64 })
}

}
}
15 changes: 11 additions & 4 deletions src/errors.rs
Expand Up @@ -54,7 +54,8 @@ pub enum Error {
JsonDataError {
/// Short section of the json close to the error.
message: String,
/// Entire JSON payload.
/// Entire JSON payload. This field is toggled with the **json_data_content** feature cargo flag.
#[cfg(feature = "json_data_content")]
contents: String,
/// Character sequence at error location.
column: usize,
Expand All @@ -65,6 +66,15 @@ pub enum Error {
/// The api version returned by the server.
api_version: String,
},
/// Error emitted when the upstream response payload is beyond the maximum payload size
#[error("The upstream response payload is over the maximum: length ({payload_size})")]
OversizedResponsePayloadError {
/// The size of the response payload
payload_size: u64
},
/// Error emitted when a request times out.
#[error("Timeout error")]
RequestTimeoutError,
/// Error emitted when JSON fails to serialize.
#[error(transparent)]
JsonSerdeError {
Expand Down Expand Up @@ -107,9 +117,6 @@ pub enum Error {
#[from]
err: hyper::Error,
},
/// Error emitted when a request times out.
#[error("Timeout error")]
RequestTimeoutError,
/// Error emitted when serde fails to urlencod a struct of options
#[error(transparent)]
URLEncodedError {
Expand Down
1 change: 1 addition & 0 deletions src/read.rs
Expand Up @@ -115,6 +115,7 @@ fn decode_json_from_slice<T: DeserializeOwned>(slice: &[u8]) -> Result<Option<T>
Err(ref e) if e.is_data() => Err(JsonDataError {
message: e.to_string(),
column: e.column(),
#[cfg(feature = "json_data_content")]
contents: String::from_utf8_lossy(slice).to_string(),
}),
Err(e) if e.is_eof() => Ok(None),
Expand Down

0 comments on commit 4633cb1

Please sign in to comment.