def _key_response_put(self, request, body, bucket_name, query, key_name, headers):
    self._set_action('KEY', 'PUT', query)
    self._authenticate_and_authorize_s3_action()
    response_headers = {}
    if (query.get('uploadId') and query.get('partNumber')):
        upload_id = query['uploadId'][0]
        part_number = int(query['partNumber'][0])
        if ('x-amz-copy-source' in request.headers):
            src = unquote(request.headers.get('x-amz-copy-source')).lstrip('/')
            (src_bucket, src_key) = src.split('/', 1)
            (src_key, src_version_id) = (src_key.split('?versionId=') if ('?versionId=' in src_key) else (src_key, None))
            src_range = request.headers.get('x-amz-copy-source-range', '').split('bytes=')[(- 1)]
            try:
                (start_byte, end_byte) = src_range.split('-')
                (start_byte, end_byte) = (int(start_byte), int(end_byte))
            except ValueError:
                (start_byte, end_byte) = (None, None)
            if self.backend.get_object(src_bucket, src_key, version_id=src_version_id):
                key = self.backend.copy_part(bucket_name, upload_id, part_number, src_bucket, src_key, src_version_id, start_byte, end_byte)
            else:
                return (404, response_headers, '')
            template = self.response_template(S3_MULTIPART_UPLOAD_RESPONSE)
            response = template.render(part=key)
        else:
            key = self.backend.upload_part(bucket_name, upload_id, part_number, body)
            response = ''
        response_headers.update(key.response_dict)
        return (200, response_headers, response)
    storage_class = request.headers.get('x-amz-storage-class', 'STANDARD')
    encryption = request.headers.get('x-amz-server-side-encryption', None)
    kms_key_id = request.headers.get('x-amz-server-side-encryption-aws-kms-key-id', None)
    bucket_key_enabled = request.headers.get('x-amz-server-side-encryption-bucket-key-enabled', None)
    if (bucket_key_enabled is not None):
        bucket_key_enabled = str(bucket_key_enabled).lower()
    bucket = self.backend.get_bucket(bucket_name)
    lock_enabled = bucket.object_lock_enabled
    lock_mode = request.headers.get('x-amz-object-lock-mode', None)
    lock_until = request.headers.get('x-amz-object-lock-retain-until-date', None)
    legal_hold = request.headers.get('x-amz-object-lock-legal-hold', 'OFF')
    if (lock_mode or lock_until or (legal_hold == 'ON')):
        if (not request.headers.get('Content-Md5')):
            raise InvalidContentMD5
        if (not lock_enabled):
            raise LockNotEnabled
    elif (lock_enabled and bucket.has_default_lock):
        if (not request.headers.get('Content-Md5')):
            raise InvalidContentMD5
        lock_until = bucket.default_retention()
        lock_mode = bucket.default_lock_mode
    acl = self._acl_from_headers(request.headers)
    if (acl is None):
        acl = self.backend.get_bucket(bucket_name).acl
    tagging = self._tagging_from_headers(request.headers)
    if ('retention' in query):
        if (not lock_enabled):
            raise LockNotEnabled
        version_id = query.get('VersionId')
        retention = self._mode_until_from_xml(body)
        self.backend.put_object_retention(bucket_name, key_name, version_id=version_id, retention=retention)
        return (200, response_headers, '')
    if ('legal-hold' in query):
        if (not lock_enabled):
            raise LockNotEnabled
        version_id = query.get('VersionId')
        legal_hold_status = self._legal_hold_status_from_xml(body)
        self.backend.put_object_legal_hold(bucket_name, key_name, version_id, legal_hold_status)
        return (200, response_headers, '')
    if ('acl' in query):
        self.backend.put_object_acl(bucket_name, key_name, acl)
        return (200, response_headers, '')
    if ('tagging' in query):
        if ('versionId' in query):
            version_id = query['versionId'][0]
        else:
            version_id = None
        key = self.backend.get_object(bucket_name, key_name, version_id=version_id)
        tagging = self._tagging_from_xml(body)
        self.backend.set_key_tags(key, tagging, key_name)
        return (200, response_headers, '')
    if ('x-amz-copy-source' in request.headers):
        src_key = request.headers.get('x-amz-copy-source')
        if isinstance(src_key, bytes):
            src_key = src_key.decode('utf-8')
        src_key_parsed = urlparse(src_key)
        (src_bucket, src_key) = clean_key_name(src_key_parsed.path).lstrip('/').split('/', 1)
        src_version_id = parse_qs(src_key_parsed.query).get('versionId', [None])[0]
        key = self.backend.get_object(src_bucket, src_key, version_id=src_version_id)
        if (key is not None):
            if (key.storage_class in ['GLACIER', 'DEEP_ARCHIVE']):
                if ((key.response_dict.get('x-amz-restore') is None) or ('ongoing-request="true"' in key.response_dict.get('x-amz-restore'))):
                    raise ObjectNotInActiveTierError(key)
            self.backend.copy_object(src_bucket, src_key, bucket_name, key_name, storage=storage_class, acl=acl, src_version_id=src_version_id)
        else:
            return (404, response_headers, '')
        new_key = self.backend.get_object(bucket_name, key_name)
        mdirective = request.headers.get('x-amz-metadata-directive')
        if ((mdirective is not None) and (mdirective == 'REPLACE')):
            metadata = metadata_from_headers(request.headers)
            new_key.set_metadata(metadata, replace=True)
        tdirective = request.headers.get('x-amz-tagging-directive')
        if (tdirective == 'REPLACE'):
            tagging = self._tagging_from_headers(request.headers)
            self.backend.set_key_tags(new_key, tagging)
        template = self.response_template(S3_OBJECT_COPY_RESPONSE)
        response_headers.update(new_key.response_dict)
        return (200, response_headers, template.render(key=new_key))
    streaming_request = (hasattr(request, 'streaming') and request.streaming)
    closing_connection = (headers.get('connection') == 'close')
    if (closing_connection and streaming_request):
        new_key = self.backend.get_object(bucket_name, key_name)
    elif streaming_request:
        new_key = self.backend.append_to_key(bucket_name, key_name, body)
    else:
        new_key = self.backend.put_object(bucket_name, key_name, body, storage=storage_class, encryption=encryption, kms_key_id=kms_key_id, bucket_key_enabled=bucket_key_enabled, lock_mode=lock_mode, lock_legal_status=legal_hold, lock_until=lock_until)
        request.streaming = True
        metadata = metadata_from_headers(request.headers)
        metadata.update(metadata_from_headers(query))
        new_key.set_metadata(metadata)
        new_key.set_acl(acl)
        new_key.website_redirect_location = request.headers.get('x-amz-website-redirect-location')
        self.backend.set_key_tags(new_key, tagging)
    response_headers.update(new_key.response_dict)
    return (200, response_headers, '')
def _key_response_put(self, request, body, bucket_name, query, key_name, headers):
    self._set_action('KEY', 'PUT', query)
    self._authenticate_and_authorize_s3_action()
    response_headers = {}
    if (query.get('uploadId') and query.get('partNumber')):
        upload_id = query['uploadId'][0]
        part_number = int(query['partNumber'][0])
        if ('x-amz-copy-source' in request.headers):
            src = unquote(request.headers.get('x-amz-copy-source')).lstrip('/')
            (src_bucket, src_key) = src.split('/', 1)
            (src_key, src_version_id) = (src_key.split('?versionId=') if ('?versionId=' in src_key) else (src_key, None))
            src_range = request.headers.get('x-amz-copy-source-range', ).split('bytes=')[(- 1)]
            try:
                (start_byte, end_byte) = src_range.split('-')
                (start_byte, end_byte) = (int(start_byte), int(end_byte))
            except ValueError:
                (start_byte, end_byte) = (None, None)
            if self.backend.get_object(src_bucket, src_key, version_id=src_version_id):
                key = self.backend.copy_part(bucket_name, upload_id, part_number, src_bucket, src_key, src_version_id, start_byte, end_byte)
            else:
                return (404, response_headers, )
            template = self.response_template(S3_MULTIPART_UPLOAD_RESPONSE)
            response = template.render(part=key)
        else:
            key = self.backend.upload_part(bucket_name, upload_id, part_number, body)
            response = 
        response_headers.update(key.response_dict)
        return (200, response_headers, response)
    storage_class = request.headers.get('x-amz-storage-class', 'STANDARD')
    encryption = request.headers.get('x-amz-server-side-encryption', None)
    kms_key_id = request.headers.get('x-amz-server-side-encryption-aws-kms-key-id', None)
    bucket_key_enabled = request.headers.get('x-amz-server-side-encryption-bucket-key-enabled', None)
    if (bucket_key_enabled is not None):
        bucket_key_enabled = str(bucket_key_enabled).lower()
    bucket = self.backend.get_bucket(bucket_name)
    lock_enabled = bucket.object_lock_enabled
    lock_mode = request.headers.get('x-amz-object-lock-mode', None)
    lock_until = request.headers.get('x-amz-object-lock-retain-until-date', None)
    legal_hold = request.headers.get('x-amz-object-lock-legal-hold', 'OFF')
    if (lock_mode or lock_until or (legal_hold == 'ON')):
        if (not request.headers.get('Content-Md5')):
            raise InvalidContentMD5
        if (not lock_enabled):
            raise LockNotEnabled
    elif (lock_enabled and bucket.has_default_lock):
        if (not request.headers.get('Content-Md5')):
            raise InvalidContentMD5
        lock_until = bucket.default_retention()
        lock_mode = bucket.default_lock_mode
    acl = self._acl_from_headers(request.headers)
    if (acl is None):
        acl = self.backend.get_bucket(bucket_name).acl
    tagging = self._tagging_from_headers(request.headers)
    if ('retention' in query):
        if (not lock_enabled):
            raise LockNotEnabled
        version_id = query.get('VersionId')
        retention = self._mode_until_from_xml(body)
        self.backend.put_object_retention(bucket_name, key_name, version_id=version_id, retention=retention)
        return (200, response_headers, )
    if ('legal-hold' in query):
        if (not lock_enabled):
            raise LockNotEnabled
        version_id = query.get('VersionId')
        legal_hold_status = self._legal_hold_status_from_xml(body)
        self.backend.put_object_legal_hold(bucket_name, key_name, version_id, legal_hold_status)
        return (200, response_headers, )
    if ('acl' in query):
        self.backend.put_object_acl(bucket_name, key_name, acl)
        return (200, response_headers, )
    if ('tagging' in query):
        if ('versionId' in query):
            version_id = query['versionId'][0]
        else:
            version_id = None
        key = self.backend.get_object(bucket_name, key_name, version_id=version_id)
        tagging = self._tagging_from_xml(body)
        self.backend.set_key_tags(key, tagging, key_name)
        return (200, response_headers, )
    if ('x-amz-copy-source' in request.headers):
        src_key = request.headers.get('x-amz-copy-source')
        if isinstance(src_key, bytes):
            src_key = src_key.decode('utf-8')
        src_key_parsed = urlparse(src_key)
        (src_bucket, src_key) = clean_key_name(src_key_parsed.path).lstrip('/').split('/', 1)
        src_version_id = parse_qs(src_key_parsed.query).get('versionId', [None])[0]
        key = self.backend.get_object(src_bucket, src_key, version_id=src_version_id)
        if (key is not None):
            if (key.storage_class in ['GLACIER', 'DEEP_ARCHIVE']):
                if ((key.response_dict.get('x-amz-restore') is None) or ('ongoing-request="true"' in key.response_dict.get('x-amz-restore'))):
                    raise ObjectNotInActiveTierError(key)
            self.backend.copy_object(src_bucket, src_key, bucket_name, key_name, storage=storage_class, acl=acl, src_version_id=src_version_id)
        else:
            return (404, response_headers, )
        new_key = self.backend.get_object(bucket_name, key_name)
        mdirective = request.headers.get('x-amz-metadata-directive')
        if ((mdirective is not None) and (mdirective == 'REPLACE')):
            metadata = metadata_from_headers(request.headers)
            new_key.set_metadata(metadata, replace=True)
        tdirective = request.headers.get('x-amz-tagging-directive')
        if (tdirective == 'REPLACE'):
            tagging = self._tagging_from_headers(request.headers)
            self.backend.set_key_tags(new_key, tagging)
        template = self.response_template(S3_OBJECT_COPY_RESPONSE)
        response_headers.update(new_key.response_dict)
        return (200, response_headers, template.render(key=new_key))
    streaming_request = (hasattr(request, 'streaming') and request.streaming)
    closing_connection = (headers.get('connection') == 'close')
    if (closing_connection and streaming_request):
        new_key = self.backend.get_object(bucket_name, key_name)
    elif streaming_request:
        new_key = self.backend.append_to_key(bucket_name, key_name, body)
    else:
        new_key = self.backend.put_object(bucket_name, key_name, body, storage=storage_class, encryption=encryption, kms_key_id=kms_key_id, bucket_key_enabled=bucket_key_enabled, lock_mode=lock_mode, lock_legal_status=legal_hold, lock_until=lock_until)
        request.streaming = True
        metadata = metadata_from_headers(request.headers)
        metadata.update(metadata_from_headers(query))
        new_key.set_metadata(metadata)
        new_key.set_acl(acl)
        new_key.website_redirect_location = request.headers.get('x-amz-website-redirect-location')
        self.backend.set_key_tags(new_key, tagging)
    response_headers.update(new_key.response_dict)
    return (200, response_headers, )