Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions ldk-server-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ const MAX_GRPC_UNARY_RESPONSE_LEN: usize = 10 * 1024 * 1024;
// constrained by this limit.
const MAX_GRPC_STREAM_MESSAGE_LEN: usize = 4 * 1024 * 1024;

// Applies to the complete Prometheus metrics response body.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we update the docs for this as well? Prometheus exposes a body_size_limit field in the config file that users can use to limit the number of bytes acceptable in the response body per scrape. Given that this change supersedes that, I believe it's worth documenting.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eh, we should never hit this, this is just some added safety in the client.

const MAX_METRICS_RESPONSE_LEN: usize = 10 * 1024 * 1024;

/// Client to access a hosted instance of LDK Server via gRPC.
///
/// The client requires the server's TLS certificate to be provided for verification.
Expand Down Expand Up @@ -156,7 +159,7 @@ impl LdkServerClient {
if let (Some(u), Some(p)) = (username, password) {
builder = builder.basic_auth(u, Some(p));
}
let response = builder.send().await.map_err(|e| {
let mut response = builder.send().await.map_err(|e| {
LdkServerError::new(InternalError, format!("HTTP request failed: {}", e))
})?;
if !response.status().is_success() {
Expand All @@ -165,10 +168,30 @@ impl LdkServerClient {
format!("Metrics request failed with status {}", response.status()),
));
}
let payload = response.bytes().await.map_err(|e| {
let too_large = || {
LdkServerError::new(
InternalError,
format!(
"Metrics response exceeds maximum size of {} bytes",
MAX_METRICS_RESPONSE_LEN
),
)
};
let capacity = match response.content_length() {
Some(len) if len > MAX_METRICS_RESPONSE_LEN as u64 => return Err(too_large()),
Some(len) => len as usize,
None => 0,
};
let mut payload = Vec::with_capacity(capacity);
while let Some(chunk) = response.chunk().await.map_err(|e| {
LdkServerError::new(InternalError, format!("Failed to read response body: {}", e))
})?;
String::from_utf8(payload.to_vec()).map_err(|e| {
})? {
if payload.len() + chunk.len() > MAX_METRICS_RESPONSE_LEN {
return Err(too_large());
}
payload.extend_from_slice(&chunk);
}
String::from_utf8(payload).map_err(|e| {
LdkServerError::new(
InternalError,
format!("Failed to decode metrics response as string: {}", e),
Expand Down
Loading