diff --git a/script/test-smoke.sh b/script/test-smoke.sh
index 2505ae38..b85d9ed5 100755
--- a/script/test-smoke.sh
+++ b/script/test-smoke.sh
@@ -116,21 +116,7 @@ if [ -z "$SKIP_DUCK" ]; then
done
fi
-rm /tmp/garage.{1..3}.{rnd,b64}
-
-if [ -z "$SKIP_AWS" ]; then
- echo "๐งช Website Testing"
- echo "
hello world
" > /tmp/garage-index.html
- aws s3 cp /tmp/garage-index.html s3://eprouvette/index.html
- [ `curl -s -o /dev/null -w "%{http_code}" --header "Host: eprouvette.garage.tld" http://127.0.0.1:3921/ ` == 404 ]
- garage -c /tmp/config.1.toml bucket website --allow eprouvette
- [ `curl -s -o /dev/null -w "%{http_code}" --header "Host: eprouvette.garage.tld" http://127.0.0.1:3921/ ` == 200 ]
- garage -c /tmp/config.1.toml bucket website --deny eprouvette
- [ `curl -s -o /dev/null -w "%{http_code}" --header "Host: eprouvette.garage.tld" http://127.0.0.1:3921/ ` == 404 ]
- aws s3 rm s3://eprouvette/index.html
- rm /tmp/garage-index.html
-fi
-
+# Advanced testing via S3API
if [ -z "$SKIP_AWS" ]; then
echo "๐ Test S3API"
@@ -265,8 +251,61 @@ if [ -z "$SKIP_AWS" ]; then
aws s3api abort-multipart-upload --bucket eprouvette --key $key --upload-id $uid;
echo "Deleted ${key}:${uid}"
done
+
+ # Test for UploadPartCopy
+ aws s3 cp "/tmp/garage.3.rnd" "s3://eprouvette/copy_part_source"
+ UPLOAD_ID=$(aws s3api create-multipart-upload --bucket eprouvette --key test_multipart | jq -r .UploadId)
+ PART1=$(aws s3api upload-part \
+ --bucket eprouvette --key test_multipart \
+ --upload-id $UPLOAD_ID --part-number 1 \
+ --body /tmp/garage.2.rnd | jq .ETag)
+ PART2=$(aws s3api upload-part-copy \
+ --bucket eprouvette --key test_multipart \
+ --upload-id $UPLOAD_ID --part-number 2 \
+ --copy-source "/eprouvette/copy_part_source" \
+ --copy-source-range "bytes=500-5000500" \
+ | jq .CopyPartResult.ETag)
+ PART3=$(aws s3api upload-part \
+ --bucket eprouvette --key test_multipart \
+ --upload-id $UPLOAD_ID --part-number 3 \
+ --body /tmp/garage.3.rnd | jq .ETag)
+ cat >/tmp/garage.multipart_struct < /tmp/garage.test_multipart_reference
+ diff /tmp/garage.test_multipart /tmp/garage.test_multipart_reference >/tmp/garage.test_multipart_diff 2>&1
+
+ aws s3 rm "s3://eprouvette/copy_part_source"
+ aws s3 rm "s3://eprouvette/test_multipart"
+
+ rm /tmp/garage.multipart_struct
+ rm /tmp/garage.test_multipart
+ rm /tmp/garage.test_multipart_reference
+ rm /tmp/garage.test_multipart_diff
fi
+rm /tmp/garage.{1..3}.{rnd,b64}
+
if [ -z "$SKIP_AWS" ]; then
echo "๐ชฃ Test bucket logic "
AWS_ACCESS_KEY_ID=`cat /tmp/garage.s3 |cut -d' ' -f1`
@@ -282,6 +321,19 @@ if [ -z "$SKIP_AWS" ]; then
[ $(aws s3 ls | wc -l) == 1 ]
fi
+if [ -z "$SKIP_AWS" ]; then
+ echo "๐งช Website Testing"
+ echo "hello world
" > /tmp/garage-index.html
+ aws s3 cp /tmp/garage-index.html s3://eprouvette/index.html
+ [ `curl -s -o /dev/null -w "%{http_code}" --header "Host: eprouvette.garage.tld" http://127.0.0.1:3921/ ` == 404 ]
+ garage -c /tmp/config.1.toml bucket website --allow eprouvette
+ [ `curl -s -o /dev/null -w "%{http_code}" --header "Host: eprouvette.garage.tld" http://127.0.0.1:3921/ ` == 200 ]
+ garage -c /tmp/config.1.toml bucket website --deny eprouvette
+ [ `curl -s -o /dev/null -w "%{http_code}" --header "Host: eprouvette.garage.tld" http://127.0.0.1:3921/ ` == 404 ]
+ aws s3 rm s3://eprouvette/index.html
+ rm /tmp/garage-index.html
+fi
+
echo "๐ Teardown"
AWS_ACCESS_KEY_ID=`cat /tmp/garage.s3 |cut -d' ' -f1`
AWS_SECRET_ACCESS_KEY=`cat /tmp/garage.s3 |cut -d' ' -f2`
diff --git a/src/api/s3_copy.rs b/src/api/s3_copy.rs
index c37bb138..7e91ecd8 100644
--- a/src/api/s3_copy.rs
+++ b/src/api/s3_copy.rs
@@ -537,6 +537,7 @@ impl CopyPreconditionHeaders {
}
(None, None, Some(inm), None) => !inm.iter().any(|x| x == etag || x == "*"),
(None, None, None, Some(ims)) => v_date > *ims,
+ (None, None, None, None) => true,
_ => {
return Err(Error::BadRequest(
"Invalid combination of x-amz-copy-source-if-xxxxx headers".into(),
diff --git a/src/api/signature.rs b/src/api/signature.rs
index c580cb3a..311e6a9a 100644
--- a/src/api/signature.rs
+++ b/src/api/signature.rs
@@ -266,10 +266,13 @@ fn canonical_header_string(headers: &HashMap, signed_headers: &s
let mut items = headers
.iter()
.filter(|(key, _)| signed_headers_vec.contains(&key.as_str()))
- .map(|(key, value)| key.to_lowercase() + ":" + value.trim())
.collect::>();
- items.sort();
- items.join("\n")
+ items.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
+ items
+ .iter()
+ .map(|(key, value)| key.to_lowercase() + ":" + value.trim())
+ .collect::>()
+ .join("\n")
}
fn canonical_query_string(uri: &hyper::Uri) -> String {