mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-06 04:47:42 +00:00
Merge branch 'main-v1' into merge-v1
This commit is contained in:
@@ -26,7 +26,7 @@ pub enum Error {
|
||||
NoSuchAdminToken(String),
|
||||
|
||||
/// The API access key does not exist
|
||||
#[error("Access key not found: {00}")]
|
||||
#[error("Access key not found: {0}")]
|
||||
NoSuchAccessKey(String),
|
||||
|
||||
/// The requested block does not exist
|
||||
|
||||
@@ -105,7 +105,7 @@ fn check_standard_signature(
|
||||
// Verify that all necessary request headers are included in signed_headers
|
||||
// The following must be included for all signatures:
|
||||
// - the Host header (mandatory)
|
||||
// - all x-amz-* headers used in the request
|
||||
// - all x-amz-* headers used in the request (except x-amz-content-sha256)
|
||||
// AWS also indicates that the Content-Type header should be signed if
|
||||
// it is used, but Minio client doesn't sign it so we don't check it for compatibility.
|
||||
let signed_headers = split_signed_headers(&authorization)?;
|
||||
@@ -152,7 +152,7 @@ fn check_presigned_signature(
|
||||
// Verify that all necessary request headers are included in signed_headers
|
||||
// For AWSv4 pre-signed URLs, the following must be included:
|
||||
// - the Host header (mandatory)
|
||||
// - all x-amz-* headers used in the request
|
||||
// - all x-amz-* headers used in the request (except x-amz-content-sha256)
|
||||
let signed_headers = split_signed_headers(&authorization)?;
|
||||
verify_signed_headers(request.headers(), &signed_headers)?;
|
||||
|
||||
@@ -269,7 +269,9 @@ fn verify_signed_headers(headers: &HeaderMap, signed_headers: &[HeaderName]) ->
|
||||
return Err(Error::bad_request("Header `Host` should be signed"));
|
||||
}
|
||||
for (name, _) in headers.iter() {
|
||||
if name.as_str().starts_with("x-amz-") {
|
||||
// Enforce signature of all x-amz-* headers, except x-amz-content-sh256
|
||||
// because it is included in the canonical request in all cases
|
||||
if name.as_str().starts_with("x-amz-") && name != X_AMZ_CONTENT_SHA256 {
|
||||
if !signed_headers.contains(name) {
|
||||
return Err(Error::bad_request(format!(
|
||||
"Header `{}` should be signed",
|
||||
@@ -475,8 +477,7 @@ impl Authorization {
|
||||
|
||||
let date = headers
|
||||
.get(X_AMZ_DATE)
|
||||
.ok_or_bad_request("Missing X-Amz-Date field")
|
||||
.map_err(Error::from)?
|
||||
.ok_or_bad_request("Missing X-Amz-Date field")?
|
||||
.to_str()?;
|
||||
let date = parse_date(date)?;
|
||||
|
||||
|
||||
+3
-1
@@ -853,7 +853,9 @@ impl PreconditionHeaders {
|
||||
}
|
||||
|
||||
fn check(&self, v: &ObjectVersion, etag: &str) -> Result<Option<StatusCode>, Error> {
|
||||
let v_date = UNIX_EPOCH + Duration::from_millis(v.timestamp);
|
||||
// we store date with ms precision, but headers are precise to the second: truncate
|
||||
// the timestamp to handle the same-second edge case
|
||||
let v_date = UNIX_EPOCH + Duration::from_secs(v.timestamp / 1000);
|
||||
|
||||
// Implemented from https://datatracker.ietf.org/doc/html/rfc7232#section-6
|
||||
|
||||
|
||||
+1
-3
@@ -39,8 +39,6 @@ use crate::encryption::{EncryptionParams, OekDerivationInfo};
|
||||
use crate::error::*;
|
||||
use crate::website::X_AMZ_WEBSITE_REDIRECT_LOCATION;
|
||||
|
||||
const PUT_BLOCKS_MAX_PARALLEL: usize = 3;
|
||||
|
||||
pub(crate) struct SaveStreamResult {
|
||||
pub(crate) version_uuid: Uuid,
|
||||
pub(crate) version_timestamp: u64,
|
||||
@@ -507,7 +505,7 @@ pub(crate) async fn read_and_put_blocks<S: Stream<Item = Result<Bytes, Error>> +
|
||||
};
|
||||
let recv_next = async {
|
||||
// If more than a maximum number of writes are in progress, don't add more for now
|
||||
if currently_running >= PUT_BLOCKS_MAX_PARALLEL {
|
||||
if currently_running >= ctx.garage.config.block_max_concurrent_writes_per_request {
|
||||
futures::future::pending().await
|
||||
} else {
|
||||
block_rx3.recv().await
|
||||
|
||||
@@ -198,6 +198,7 @@ async fn test_precondition() {
|
||||
);
|
||||
}
|
||||
let older_date = DateTime::from_secs_f64(last_modified.as_secs_f64() - 10.0);
|
||||
let same_date = DateTime::from_secs_f64(last_modified.as_secs_f64());
|
||||
let newer_date = DateTime::from_secs_f64(last_modified.as_secs_f64() + 10.0);
|
||||
{
|
||||
let err = ctx
|
||||
@@ -212,6 +213,18 @@ async fn test_precondition() {
|
||||
matches!(err, Err(SdkError::ServiceError(se)) if se.raw().status().as_u16() == 304)
|
||||
);
|
||||
|
||||
let err = ctx
|
||||
.client
|
||||
.get_object()
|
||||
.bucket(&bucket)
|
||||
.key(STD_KEY)
|
||||
.if_modified_since(same_date)
|
||||
.send()
|
||||
.await;
|
||||
assert!(
|
||||
matches!(err, Err(SdkError::ServiceError(se)) if se.raw().status().as_u16() == 304)
|
||||
);
|
||||
|
||||
let o = ctx
|
||||
.client
|
||||
.get_object()
|
||||
@@ -236,6 +249,17 @@ async fn test_precondition() {
|
||||
matches!(err, Err(SdkError::ServiceError(se)) if se.raw().status().as_u16() == 412)
|
||||
);
|
||||
|
||||
let o = ctx
|
||||
.client
|
||||
.get_object()
|
||||
.bucket(&bucket)
|
||||
.key(STD_KEY)
|
||||
.if_unmodified_since(same_date)
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(o.e_tag.as_ref().unwrap().as_str(), etag);
|
||||
|
||||
let o = ctx
|
||||
.client
|
||||
.get_object()
|
||||
|
||||
@@ -45,6 +45,11 @@ pub struct Config {
|
||||
)]
|
||||
pub block_size: usize,
|
||||
|
||||
/// Maximum number of parallel block writes per PUT request
|
||||
/// Higher values improve throughput but increase memory usage
|
||||
/// Default: 3, Recommended: 10-30 for NVMe, 3-10 for HDD
|
||||
#[serde(default = "default_block_max_concurrent_writes_per_request")]
|
||||
pub block_max_concurrent_writes_per_request: usize,
|
||||
/// Number of replicas. Can be any positive integer, but uneven numbers are more favorable.
|
||||
/// - 1 for single-node clusters, or to disable replication
|
||||
/// - 3 is the recommended and supported setting.
|
||||
@@ -272,6 +277,9 @@ pub struct KubernetesDiscoveryConfig {
|
||||
pub skip_crd: bool,
|
||||
}
|
||||
|
||||
pub fn default_block_max_concurrent_writes_per_request() -> usize {
|
||||
3
|
||||
}
|
||||
/// Read and parse configuration
|
||||
pub fn read_config(config_file: PathBuf) -> Result<Config, Error> {
|
||||
let config = std::fs::read_to_string(config_file)?;
|
||||
|
||||
Reference in New Issue
Block a user