diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 80a0a9421..5f1be0fbb 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -80,19 +80,17 @@ def key_response(uri_info, method, body, headers): s3_backend.copy_key(src_bucket, src_key, bucket_name, key_name) template = Template(S3_OBJECT_COPY_RESPONSE) return template.render(key=src_key) - if body is not None: - key = s3_backend.get_key(bucket_name, key_name) - if not key or body: - # We want to write the key in once of two circumstances. - # - The key does not currently exist. - # - The key already exists, but body is a truthy value. - # This allows us to write empty strings to keys for the first - # write, but not subsequent. This is because HTTPretty sends - # an empty string on connection close. This is a temporary fix - # while HTTPretty gets fixed. - new_key = s3_backend.set_key(bucket_name, key_name, body) - template = Template(S3_OBJECT_RESPONSE) - return template.render(key=new_key), dict(etag=new_key.etag) + content_length = int(headers.get('Content-Length', 0)) + if body or (body == '' and content_length == 0): + # We want to write the key in once of two circumstances. + # - Anytime we are given a truthy body value + # - We are given an empty body value and the content length is zero. + # The reason we do not set the key to an empty string if the + # content length is not zero is because we are sometimes sent an + # empty string as part of closing the connection. + new_key = s3_backend.set_key(bucket_name, key_name, body) + template = Template(S3_OBJECT_RESPONSE) + return template.render(key=new_key), dict(etag=new_key.etag) key = s3_backend.get_key(bucket_name, key_name) if key: return "", dict(etag=key.etag) diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 31e011bfc..278ce9e2f 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -62,6 +62,20 @@ def test_empty_key(): bucket.get_key("the-key").get_contents_as_string().should.equal('') +@mock_s3 +def test_empty_key_set_on_existing_key(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket("foobar") + key = Key(bucket) + key.key = "the-key" + key.set_contents_from_string("foobar") + + bucket.get_key("the-key").get_contents_as_string().should.equal('foobar') + + key.set_contents_from_string("") + bucket.get_key("the-key").get_contents_as_string().should.equal('') + + @mock_s3 def test_copy_key(): conn = boto.connect_s3('the_key', 'the_secret')