From 309d5eb3bc60eb46e8322a59b3f7a0f10ac841ce Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Thu, 5 Oct 2023 07:43:53 +0000 Subject: [PATCH] S3: ContentLength-headers should be strings (#6884) --- moto/s3/responses.py | 6 +++--- tests/test_s3/test_s3_multipart.py | 32 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index d55f73381..89be2257e 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -1190,7 +1190,7 @@ class S3Response(BaseResponse): response_headers["content-range"] = f"bytes {begin}-{end}/{length}" content = response_content[begin : end + 1] - response_headers["content-length"] = len(content) + response_headers["content-length"] = str(len(content)) return 206, response_headers, content def _handle_v4_chunk_signatures(self, body: bytes, content_length: int) -> bytes: @@ -1518,7 +1518,7 @@ class S3Response(BaseResponse): ) response = "" response_headers.update(key.response_dict) - response_headers["content-length"] = len(response) + response_headers["content-length"] = str(len(response)) return 200, response_headers, response storage_class = request.headers.get("x-amz-storage-class", "STANDARD") @@ -1701,7 +1701,7 @@ class S3Response(BaseResponse): template = self.response_template(S3_OBJECT_COPY_RESPONSE) response_headers.update(new_key.response_dict) response = template.render(key=new_key) - response_headers["content-length"] = len(response) + response_headers["content-length"] = str(len(response)) return 200, response_headers, response # Initial data diff --git a/tests/test_s3/test_s3_multipart.py b/tests/test_s3/test_s3_multipart.py index 0040c0c3a..b3925dff8 100644 --- a/tests/test_s3/test_s3_multipart.py +++ b/tests/test_s3/test_s3_multipart.py @@ -7,6 +7,7 @@ import boto3 from botocore.client import ClientError import pytest import requests +from unittest import SkipTest from moto import settings, mock_s3 import moto.s3.models as s3model @@ -1027,3 +1028,34 @@ def test_head_object_returns_part_count(): # Header is not returned when we do not pass PartNumber resp = client.head_object(Bucket=bucket, Key=key) assert "PartsCount" not in resp + + +@mock_s3 +@reduced_min_part_size +def test_generate_presigned_url_for_multipart_upload(): + if not settings.TEST_DECORATOR_MODE: + raise SkipTest("No point in testing this outside decorator mode") + bucket_name = "mock-bucket" + file_name = "mock-file" + s3_client = boto3.client("s3") + s3_client.create_bucket(Bucket=bucket_name) + + mpu = s3_client.create_multipart_upload( + Bucket=bucket_name, + Key=file_name, + ) + upload_id = mpu["UploadId"] + + url = s3_client.generate_presigned_url( + "upload_part", + Params={ + "Bucket": bucket_name, + "Key": file_name, + "PartNumber": 1, + "UploadId": upload_id, + }, + ) + data = b"0" * REDUCED_PART_SIZE + + resp = requests.put(url, data=data) + assert resp.status_code == 200