Cleanup headers and encoding.
This commit is contained in:
parent
468a1b970c
commit
cad185c74d
@ -331,7 +331,7 @@ class RestAPI(object):
|
||||
|
||||
def update_integration_mocks(self, stage_name):
|
||||
stage_url = STAGE_URL.format(api_id=self.id, region_name=self.region_name, stage_name=stage_name)
|
||||
responses.add_callback(responses.GET, stage_url, callback=self.resource_callback)
|
||||
responses.add_callback(responses.GET, stage_url.lower(), callback=self.resource_callback)
|
||||
|
||||
def create_stage(self, name, deployment_id,variables=None,description='',cacheClusterEnabled=None,cacheClusterSize=None):
|
||||
if variables is None:
|
||||
|
@ -10,11 +10,11 @@ from .exceptions import StageNotFoundException
|
||||
class APIGatewayResponse(BaseResponse):
|
||||
|
||||
def _get_param(self, key):
|
||||
return json.loads(self.body.decode("ascii")).get(key)
|
||||
return json.loads(self.body).get(key)
|
||||
|
||||
|
||||
def _get_param_with_default_value(self, key, default):
|
||||
jsonbody = json.loads(self.body.decode("ascii"))
|
||||
jsonbody = json.loads(self.body)
|
||||
|
||||
if key in jsonbody:
|
||||
return jsonbody.get(key)
|
||||
@ -30,14 +30,14 @@ class APIGatewayResponse(BaseResponse):
|
||||
|
||||
if self.method == 'GET':
|
||||
apis = self.backend.list_apis()
|
||||
return 200, headers, json.dumps({"item": [
|
||||
return 200, {}, json.dumps({"item": [
|
||||
api.to_dict() for api in apis
|
||||
]})
|
||||
elif self.method == 'POST':
|
||||
name = self._get_param('name')
|
||||
description = self._get_param('description')
|
||||
rest_api = self.backend.create_rest_api(name, description)
|
||||
return 200, headers, json.dumps(rest_api.to_dict())
|
||||
return 200, {}, json.dumps(rest_api.to_dict())
|
||||
|
||||
def restapis_individual(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -45,10 +45,10 @@ class APIGatewayResponse(BaseResponse):
|
||||
|
||||
if self.method == 'GET':
|
||||
rest_api = self.backend.get_rest_api(function_id)
|
||||
return 200, headers, json.dumps(rest_api.to_dict())
|
||||
return 200, {}, json.dumps(rest_api.to_dict())
|
||||
elif self.method == 'DELETE':
|
||||
rest_api = self.backend.delete_rest_api(function_id)
|
||||
return 200, headers, json.dumps(rest_api.to_dict())
|
||||
return 200, {}, json.dumps(rest_api.to_dict())
|
||||
|
||||
def resources(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -56,7 +56,7 @@ class APIGatewayResponse(BaseResponse):
|
||||
|
||||
if self.method == 'GET':
|
||||
resources = self.backend.list_resources(function_id)
|
||||
return 200, headers, json.dumps({"item": [
|
||||
return 200, {}, json.dumps({"item": [
|
||||
resource.to_dict() for resource in resources
|
||||
]})
|
||||
|
||||
@ -72,7 +72,7 @@ class APIGatewayResponse(BaseResponse):
|
||||
resource = self.backend.create_resource(function_id, resource_id, path_part)
|
||||
elif self.method == 'DELETE':
|
||||
resource = self.backend.delete_resource(function_id, resource_id)
|
||||
return 200, headers, json.dumps(resource.to_dict())
|
||||
return 200, {}, json.dumps(resource.to_dict())
|
||||
|
||||
def resource_methods(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -83,11 +83,11 @@ class APIGatewayResponse(BaseResponse):
|
||||
|
||||
if self.method == 'GET':
|
||||
method = self.backend.get_method(function_id, resource_id, method_type)
|
||||
return 200, headers, json.dumps(method)
|
||||
return 200, {}, json.dumps(method)
|
||||
elif self.method == 'PUT':
|
||||
authorization_type = self._get_param("authorizationType")
|
||||
method = self.backend.create_method(function_id, resource_id, method_type, authorization_type)
|
||||
return 200, headers, json.dumps(method)
|
||||
return 200, {}, json.dumps(method)
|
||||
|
||||
def resource_method_responses(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -103,7 +103,7 @@ class APIGatewayResponse(BaseResponse):
|
||||
method_response = self.backend.create_method_response(function_id, resource_id, method_type, response_code)
|
||||
elif self.method == 'DELETE':
|
||||
method_response = self.backend.delete_method_response(function_id, resource_id, method_type, response_code)
|
||||
return 200, headers, json.dumps(method_response)
|
||||
return 200, {}, json.dumps(method_response)
|
||||
|
||||
def restapis_stages(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -123,9 +123,9 @@ class APIGatewayResponse(BaseResponse):
|
||||
cacheClusterEnabled=cacheClusterEnabled, cacheClusterSize=cacheClusterSize)
|
||||
elif self.method == 'GET':
|
||||
stages = self.backend.get_stages(function_id)
|
||||
return 200, headers, json.dumps({"item": stages})
|
||||
return 200, {}, json.dumps({"item": stages})
|
||||
|
||||
return 200, headers, json.dumps(stage_response)
|
||||
return 200, {}, json.dumps(stage_response)
|
||||
|
||||
def stages(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -137,11 +137,11 @@ class APIGatewayResponse(BaseResponse):
|
||||
try:
|
||||
stage_response = self.backend.get_stage(function_id, stage_name)
|
||||
except StageNotFoundException as error:
|
||||
return error.code, headers,'{{"message":"{0}","code":"{1}"}}'.format(error.message,error.error_type)
|
||||
return error.code, {},'{{"message":"{0}","code":"{1}"}}'.format(error.message,error.error_type)
|
||||
elif self.method == 'PATCH':
|
||||
patch_operations = self._get_param('patchOperations')
|
||||
stage_response = self.backend.update_stage(function_id, stage_name, patch_operations)
|
||||
return 200, headers, json.dumps(stage_response)
|
||||
return 200, {}, json.dumps(stage_response)
|
||||
|
||||
def integrations(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -159,7 +159,7 @@ class APIGatewayResponse(BaseResponse):
|
||||
integration_response = self.backend.create_integration(function_id, resource_id, method_type, integration_type, uri, request_templates=request_templates)
|
||||
elif self.method == 'DELETE':
|
||||
integration_response = self.backend.delete_integration(function_id, resource_id, method_type)
|
||||
return 200, headers, json.dumps(integration_response)
|
||||
return 200, {}, json.dumps(integration_response)
|
||||
|
||||
def integration_responses(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -182,7 +182,7 @@ class APIGatewayResponse(BaseResponse):
|
||||
integration_response = self.backend.delete_integration_response(
|
||||
function_id, resource_id, method_type, status_code
|
||||
)
|
||||
return 200, headers, json.dumps(integration_response)
|
||||
return 200, {}, json.dumps(integration_response)
|
||||
|
||||
def deployments(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -190,13 +190,13 @@ class APIGatewayResponse(BaseResponse):
|
||||
|
||||
if self.method == 'GET':
|
||||
deployments = self.backend.get_deployments(function_id)
|
||||
return 200, headers, json.dumps({"item": deployments})
|
||||
return 200, {}, json.dumps({"item": deployments})
|
||||
elif self.method == 'POST':
|
||||
name = self._get_param("stageName")
|
||||
description = self._get_param_with_default_value("description","")
|
||||
stage_variables = self._get_param_with_default_value('variables',{})
|
||||
deployment = self.backend.create_deployment(function_id, name, description,stage_variables)
|
||||
return 200, headers, json.dumps(deployment)
|
||||
return 200, {}, json.dumps(deployment)
|
||||
|
||||
def individual_deployment(self, request, full_url, headers):
|
||||
self.setup_class(request, full_url, headers)
|
||||
@ -208,4 +208,4 @@ class APIGatewayResponse(BaseResponse):
|
||||
deployment = self.backend.get_deployment(function_id, deployment_id)
|
||||
elif self.method == 'DELETE':
|
||||
deployment = self.backend.delete_deployment(function_id, deployment_id)
|
||||
return 200, headers, json.dumps(deployment)
|
||||
return 200, {}, json.dumps(deployment)
|
||||
|
@ -196,7 +196,7 @@ class LambdaBackend(BaseBackend):
|
||||
|
||||
def __init__(self):
|
||||
self._functions = {}
|
||||
|
||||
|
||||
def has_function(self, function_name):
|
||||
return function_name in self._functions
|
||||
|
||||
|
@ -36,6 +36,7 @@ class LambdaResponse(BaseResponse):
|
||||
raise ValueError("Cannot handle request")
|
||||
|
||||
def _invoke(self, request, full_url, headers):
|
||||
response_headers = {}
|
||||
lambda_backend = self.get_lambda_backend(full_url)
|
||||
|
||||
path = request.path if hasattr(request, 'path') else request.path_url
|
||||
@ -43,15 +44,15 @@ class LambdaResponse(BaseResponse):
|
||||
|
||||
if lambda_backend.has_function(function_name):
|
||||
fn = lambda_backend.get_function(function_name)
|
||||
payload = fn.invoke(request, headers)
|
||||
headers['Content-Length'] = str(len(payload))
|
||||
return 202, headers, payload
|
||||
payload = fn.invoke(request, response_headers)
|
||||
response_headers['Content-Length'] = str(len(payload))
|
||||
return 202, response_headers, payload
|
||||
else:
|
||||
return 404, headers, "{}"
|
||||
return 404, response_headers, "{}"
|
||||
|
||||
def _list_functions(self, request, full_url, headers):
|
||||
lambda_backend = self.get_lambda_backend(full_url)
|
||||
return 200, headers, json.dumps({
|
||||
return 200, {}, json.dumps({
|
||||
"Functions": [fn.get_configuration() for fn in lambda_backend.list_functions()],
|
||||
# "NextMarker": str(uuid.uuid4()),
|
||||
})
|
||||
@ -62,10 +63,10 @@ class LambdaResponse(BaseResponse):
|
||||
try:
|
||||
fn = lambda_backend.create_function(spec)
|
||||
except ValueError as e:
|
||||
return 400, headers, json.dumps({"Error": {"Code": e.args[0], "Message": e.args[1]}})
|
||||
return 400, {}, json.dumps({"Error": {"Code": e.args[0], "Message": e.args[1]}})
|
||||
else:
|
||||
config = fn.get_configuration()
|
||||
return 201, headers, json.dumps(config)
|
||||
return 201, {}, json.dumps(config)
|
||||
|
||||
def _delete_function(self, request, full_url, headers):
|
||||
lambda_backend = self.get_lambda_backend(full_url)
|
||||
@ -75,9 +76,9 @@ class LambdaResponse(BaseResponse):
|
||||
|
||||
if lambda_backend.has_function(function_name):
|
||||
lambda_backend.delete_function(function_name)
|
||||
return 204, headers, ""
|
||||
return 204, {}, ""
|
||||
else:
|
||||
return 404, headers, "{}"
|
||||
return 404, {}, "{}"
|
||||
|
||||
def _get_function(self, request, full_url, headers):
|
||||
lambda_backend = self.get_lambda_backend(full_url)
|
||||
@ -88,9 +89,9 @@ class LambdaResponse(BaseResponse):
|
||||
if lambda_backend.has_function(function_name):
|
||||
fn = lambda_backend.get_function(function_name)
|
||||
code = fn.get_code()
|
||||
return 200, headers, json.dumps(code)
|
||||
return 200, {}, json.dumps(code)
|
||||
else:
|
||||
return 404, headers, "{}"
|
||||
return 404, {}, "{}"
|
||||
|
||||
def get_lambda_backend(self, full_url):
|
||||
from moto.awslambda.models import lambda_backends
|
||||
|
@ -8,7 +8,11 @@ import re
|
||||
from moto.packages.responses import responses
|
||||
from moto.packages.httpretty import HTTPretty
|
||||
from .responses import metadata_response
|
||||
from .utils import convert_regex_to_flask_path, convert_flask_to_responses_response
|
||||
from .utils import (
|
||||
convert_httpretty_response,
|
||||
convert_regex_to_flask_path,
|
||||
convert_flask_to_responses_response,
|
||||
)
|
||||
|
||||
class BaseMockAWS(object):
|
||||
nested_count = 0
|
||||
@ -93,14 +97,14 @@ class HttprettyMockAWS(BaseMockAWS):
|
||||
HTTPretty.register_uri(
|
||||
method=method,
|
||||
uri=re.compile(key),
|
||||
body=value,
|
||||
body=convert_httpretty_response(value),
|
||||
)
|
||||
|
||||
# Mock out localhost instance metadata
|
||||
HTTPretty.register_uri(
|
||||
method=method,
|
||||
uri=re.compile('http://169.254.169.254/latest/meta-data/.*'),
|
||||
body=metadata_response
|
||||
body=convert_httpretty_response(metadata_response),
|
||||
)
|
||||
|
||||
def disable_patching(self):
|
||||
|
@ -123,14 +123,14 @@ class BaseResponse(_TemplateEnvironmentMixin):
|
||||
for key, value in request.form.items():
|
||||
querystring[key] = [value, ]
|
||||
|
||||
if isinstance(self.body, six.binary_type):
|
||||
self.body = self.body.decode('utf-8')
|
||||
|
||||
if not querystring:
|
||||
querystring.update(parse_qs(urlparse(full_url).query, keep_blank_values=True))
|
||||
if not querystring:
|
||||
if 'json' in request.headers.get('content-type', []) and self.aws_service_spec:
|
||||
if isinstance(self.body, six.binary_type):
|
||||
decoded = json.loads(self.body.decode('utf-8'))
|
||||
else:
|
||||
decoded = json.loads(self.body)
|
||||
decoded = json.loads(self.body)
|
||||
|
||||
target = request.headers.get('x-amz-target') or request.headers.get('X-Amz-Target')
|
||||
service, method = target.split('.')
|
||||
@ -154,7 +154,7 @@ class BaseResponse(_TemplateEnvironmentMixin):
|
||||
self.headers = request.headers
|
||||
if 'host' not in self.headers:
|
||||
self.headers['host'] = urlparse(full_url).netloc
|
||||
self.response_headers = headers
|
||||
self.response_headers = {"server": "amazon.com"}
|
||||
|
||||
def get_region_from_url(self, full_url):
|
||||
match = re.search(self.region_regex, full_url)
|
||||
|
@ -79,6 +79,29 @@ def convert_regex_to_flask_path(url_path):
|
||||
return url_path
|
||||
|
||||
|
||||
class convert_httpretty_response(object):
|
||||
|
||||
def __init__(self, callback):
|
||||
self.callback = callback
|
||||
|
||||
@property
|
||||
def __name__(self):
|
||||
# For instance methods, use class and method names. Otherwise
|
||||
# use module and method name
|
||||
if inspect.ismethod(self.callback):
|
||||
outer = self.callback.__self__.__class__.__name__
|
||||
else:
|
||||
outer = self.callback.__module__
|
||||
return "{0}.{1}".format(outer, self.callback.__name__)
|
||||
|
||||
def __call__(self, request, url, headers, **kwargs):
|
||||
result = self.callback(request, url, headers)
|
||||
status, headers, response = result
|
||||
if 'server' not in headers:
|
||||
headers["server"] = "amazon.com"
|
||||
return status, headers, response
|
||||
|
||||
|
||||
class convert_flask_to_httpretty_response(object):
|
||||
|
||||
def __init__(self, callback):
|
||||
@ -119,8 +142,11 @@ class convert_flask_to_responses_response(object):
|
||||
return "{0}.{1}".format(outer, self.callback.__name__)
|
||||
|
||||
def __call__(self, request, *args, **kwargs):
|
||||
for key, val in request.headers.items():
|
||||
if isinstance(val, six.binary_type):
|
||||
request.headers[key] = val.decode("utf-8")
|
||||
|
||||
result = self.callback(request, request.url, request.headers)
|
||||
# result is a status, headers, response tuple
|
||||
status, headers, response = result
|
||||
return status, headers, response
|
||||
|
||||
|
@ -12,7 +12,7 @@ class DataPipelineResponse(BaseResponse):
|
||||
def parameters(self):
|
||||
# TODO this should really be moved to core/responses.py
|
||||
if self.body:
|
||||
return json.loads(self.body.decode("utf-8"))
|
||||
return json.loads(self.body)
|
||||
else:
|
||||
return self.querystring
|
||||
|
||||
|
@ -51,7 +51,7 @@ class DynamoHandler(BaseResponse):
|
||||
return status, self.response_headers, dynamo_json_dump({'__type': type_})
|
||||
|
||||
def call_action(self):
|
||||
body = self.body.decode('utf-8')
|
||||
body = self.body
|
||||
if 'GetSessionToken' in body:
|
||||
return 200, self.response_headers, sts_handler()
|
||||
|
||||
|
@ -52,7 +52,7 @@ class DynamoHandler(BaseResponse):
|
||||
return status, self.response_headers, dynamo_json_dump({'__type': type_})
|
||||
|
||||
def call_action(self):
|
||||
body = self.body.decode('utf-8')
|
||||
body = self.body
|
||||
if 'GetSessionToken' in body:
|
||||
return 200, self.response_headers, sts_handler()
|
||||
|
||||
|
@ -14,7 +14,7 @@ class EC2ContainerServiceResponse(BaseResponse):
|
||||
@property
|
||||
def request_params(self):
|
||||
try:
|
||||
return json.loads(self.body.decode())
|
||||
return json.loads(self.body)
|
||||
except ValueError:
|
||||
return {}
|
||||
|
||||
|
@ -19,7 +19,7 @@ class EventsHandler(BaseResponse):
|
||||
}
|
||||
|
||||
def load_body(self):
|
||||
decoded_body = self.body.decode('utf-8')
|
||||
decoded_body = self.body
|
||||
return json.loads(decoded_body or '{}')
|
||||
|
||||
def error(self, type_, message='', status=400):
|
||||
|
@ -11,7 +11,7 @@ class KinesisResponse(BaseResponse):
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
return json.loads(self.body.decode("utf-8"))
|
||||
return json.loads(self.body)
|
||||
|
||||
@property
|
||||
def kinesis_backend(self):
|
||||
|
@ -22,7 +22,7 @@ class KmsResponse(BaseResponse):
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
return json.loads(self.body.decode("utf-8"))
|
||||
return json.loads(self.body)
|
||||
|
||||
@property
|
||||
def kms_backend(self):
|
||||
|
@ -10,7 +10,7 @@ class OpsWorksResponse(BaseResponse):
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
return json.loads(self.body.decode("utf-8"))
|
||||
return json.loads(self.body)
|
||||
|
||||
@property
|
||||
def opsworks_backend(self):
|
||||
|
@ -104,10 +104,10 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
try:
|
||||
response = self._bucket_response(request, full_url, headers)
|
||||
except S3ClientError as s3error:
|
||||
response = s3error.code, headers, s3error.description
|
||||
response = s3error.code, {}, s3error.description
|
||||
|
||||
if isinstance(response, six.string_types):
|
||||
return 200, headers, response.encode("utf-8")
|
||||
return 200, {}, response.encode("utf-8")
|
||||
else:
|
||||
status_code, headers, response_content = response
|
||||
return status_code, headers, response_content.encode("utf-8")
|
||||
@ -133,8 +133,9 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
# Flask server
|
||||
body = request.data
|
||||
if body is None:
|
||||
body = ''
|
||||
body = body.decode('utf-8')
|
||||
body = b''
|
||||
if isinstance(body, six.binary_type):
|
||||
body = body.decode('utf-8')
|
||||
|
||||
if method == 'HEAD':
|
||||
return self._bucket_response_head(bucket_name, headers)
|
||||
@ -151,7 +152,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
|
||||
def _bucket_response_head(self, bucket_name, headers):
|
||||
self.backend.get_bucket(bucket_name)
|
||||
return 200, headers, ""
|
||||
return 200, {}, ""
|
||||
|
||||
def _bucket_response_get(self, bucket_name, querystring, headers):
|
||||
if 'uploads' in querystring:
|
||||
@ -173,7 +174,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
elif 'lifecycle' in querystring:
|
||||
bucket = self.backend.get_bucket(bucket_name)
|
||||
if not bucket.rules:
|
||||
return 404, headers, "NoSuchLifecycleConfiguration"
|
||||
return 404, {}, "NoSuchLifecycleConfiguration"
|
||||
template = self.response_template(S3_BUCKET_LIFECYCLE_CONFIGURATION)
|
||||
return template.render(rules=bucket.rules)
|
||||
elif 'versioning' in querystring:
|
||||
@ -184,8 +185,8 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
policy = self.backend.get_bucket_policy(bucket_name)
|
||||
if not policy:
|
||||
template = self.response_template(S3_NO_POLICY)
|
||||
return 404, headers, template.render(bucket_name=bucket_name)
|
||||
return 200, headers, policy
|
||||
return 404, {}, template.render(bucket_name=bucket_name)
|
||||
return 200, {}, policy
|
||||
elif 'website' in querystring:
|
||||
website_configuration = self.backend.get_bucket_website_configuration(bucket_name)
|
||||
return website_configuration
|
||||
@ -211,7 +212,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
version_id_marker=version_id_marker
|
||||
)
|
||||
template = self.response_template(S3_BUCKET_GET_VERSIONS)
|
||||
return 200, headers, template.render(
|
||||
return 200, {}, template.render(
|
||||
key_list=versions,
|
||||
bucket=bucket,
|
||||
prefix='',
|
||||
@ -220,14 +221,14 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
is_truncated='false',
|
||||
)
|
||||
elif querystring.get('list-type', [None])[0] == '2':
|
||||
return 200, headers, self._handle_list_objects_v2(bucket_name, querystring)
|
||||
return 200, {}, self._handle_list_objects_v2(bucket_name, querystring)
|
||||
|
||||
bucket = self.backend.get_bucket(bucket_name)
|
||||
prefix = querystring.get('prefix', [None])[0]
|
||||
delimiter = querystring.get('delimiter', [None])[0]
|
||||
result_keys, result_folders = self.backend.prefix_query(bucket, prefix, delimiter)
|
||||
template = self.response_template(S3_BUCKET_GET_RESPONSE)
|
||||
return 200, headers, template.render(
|
||||
return 200, {}, template.render(
|
||||
bucket=bucket,
|
||||
prefix=prefix,
|
||||
delimiter=delimiter,
|
||||
@ -286,7 +287,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
template = self.response_template(S3_BUCKET_VERSIONING)
|
||||
return template.render(bucket_versioning_status=ver.group(1))
|
||||
else:
|
||||
return 404, headers, ""
|
||||
return 404, {}, ""
|
||||
elif 'lifecycle' in querystring:
|
||||
rules = xmltodict.parse(body)['LifecycleConfiguration']['Rule']
|
||||
if not isinstance(rules, list):
|
||||
@ -315,27 +316,27 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
else:
|
||||
raise
|
||||
template = self.response_template(S3_BUCKET_CREATE_RESPONSE)
|
||||
return 200, headers, template.render(bucket=new_bucket)
|
||||
return 200, {}, template.render(bucket=new_bucket)
|
||||
|
||||
def _bucket_response_delete(self, body, bucket_name, querystring, headers):
|
||||
if 'policy' in querystring:
|
||||
self.backend.delete_bucket_policy(bucket_name, body)
|
||||
return 204, headers, ""
|
||||
return 204, {}, ""
|
||||
elif 'lifecycle' in querystring:
|
||||
bucket = self.backend.get_bucket(bucket_name)
|
||||
bucket.delete_lifecycle()
|
||||
return 204, headers, ""
|
||||
return 204, {}, ""
|
||||
|
||||
removed_bucket = self.backend.delete_bucket(bucket_name)
|
||||
|
||||
if removed_bucket:
|
||||
# Bucket exists
|
||||
template = self.response_template(S3_DELETE_BUCKET_SUCCESS)
|
||||
return 204, headers, template.render(bucket=removed_bucket)
|
||||
return 204, {}, template.render(bucket=removed_bucket)
|
||||
else:
|
||||
# Tried to delete a bucket that still has keys
|
||||
template = self.response_template(S3_DELETE_BUCKET_WITH_ITEMS_ERROR)
|
||||
return 409, headers, template.render(bucket=removed_bucket)
|
||||
return 409, {}, template.render(bucket=removed_bucket)
|
||||
|
||||
def _bucket_response_post(self, request, body, bucket_name, headers):
|
||||
path = request.path if hasattr(request, 'path') else request.path_url
|
||||
@ -349,7 +350,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
else:
|
||||
# HTTPretty, build new form object
|
||||
form = {}
|
||||
for kv in body.decode('utf-8').split('&'):
|
||||
for kv in body.split('&'):
|
||||
k, v = kv.split('=')
|
||||
form[k] = v
|
||||
|
||||
@ -365,7 +366,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
metadata = metadata_from_headers(form)
|
||||
new_key.set_metadata(metadata)
|
||||
|
||||
return 200, headers, ""
|
||||
return 200, {}, ""
|
||||
|
||||
def _bucket_response_delete_keys(self, request, body, bucket_name, headers):
|
||||
template = self.response_template(S3_DELETE_KEYS_RESPONSE)
|
||||
@ -382,9 +383,10 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
else:
|
||||
error_names.append(key_name)
|
||||
|
||||
return 200, headers, template.render(deleted=deleted_names, delete_errors=error_names)
|
||||
return 200, {}, template.render(deleted=deleted_names, delete_errors=error_names)
|
||||
|
||||
def _handle_range_header(self, request, headers, response_content):
|
||||
response_headers = {}
|
||||
length = len(response_content)
|
||||
last = length - 1
|
||||
_, rspec = request.headers.get('range').split('=')
|
||||
@ -399,28 +401,29 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
begin = length - min(end, length)
|
||||
end = last
|
||||
else:
|
||||
return 400, headers, ""
|
||||
return 400, response_headers, ""
|
||||
if begin < 0 or end > last or begin > min(end, last):
|
||||
return 416, headers, ""
|
||||
headers['content-range'] = "bytes {0}-{1}/{2}".format(
|
||||
return 416, response_headers, ""
|
||||
response_headers['content-range'] = "bytes {0}-{1}/{2}".format(
|
||||
begin, end, length)
|
||||
return 206, headers, response_content[begin:end + 1]
|
||||
return 206, response_headers, response_content[begin:end + 1]
|
||||
|
||||
def key_response(self, request, full_url, headers):
|
||||
response_headers = {}
|
||||
try:
|
||||
response = self._key_response(request, full_url, headers)
|
||||
except S3ClientError as s3error:
|
||||
response = s3error.code, headers, s3error.description
|
||||
response = s3error.code, {}, s3error.description
|
||||
|
||||
if isinstance(response, six.string_types):
|
||||
status_code = 200
|
||||
response_content = response
|
||||
else:
|
||||
status_code, headers, response_content = response
|
||||
status_code, response_headers, response_content = response
|
||||
|
||||
if status_code == 200 and 'range' in request.headers:
|
||||
return self._handle_range_header(request, headers, response_content)
|
||||
return status_code, headers, response_content
|
||||
return self._handle_range_header(request, response_headers, response_content)
|
||||
return status_code, response_headers, response_content
|
||||
|
||||
def _key_response(self, request, full_url, headers):
|
||||
parsed_url = urlparse(full_url)
|
||||
@ -455,11 +458,12 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
raise NotImplementedError("Method {0} has not been impelemented in the S3 backend yet".format(method))
|
||||
|
||||
def _key_response_get(self, bucket_name, query, key_name, headers):
|
||||
response_headers = {}
|
||||
if query.get('uploadId'):
|
||||
upload_id = query['uploadId'][0]
|
||||
parts = self.backend.list_multipart(bucket_name, upload_id)
|
||||
template = self.response_template(S3_MULTIPART_LIST_RESPONSE)
|
||||
return 200, headers, template.render(
|
||||
return 200, response_headers, template.render(
|
||||
bucket_name=bucket_name,
|
||||
key_name=key_name,
|
||||
upload_id=upload_id,
|
||||
@ -471,13 +475,14 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
bucket_name, key_name, version_id=version_id)
|
||||
if 'acl' in query:
|
||||
template = self.response_template(S3_OBJECT_ACL_RESPONSE)
|
||||
return 200, headers, template.render(obj=key)
|
||||
return 200, response_headers, template.render(obj=key)
|
||||
|
||||
headers.update(key.metadata)
|
||||
headers.update(key.response_dict)
|
||||
return 200, headers, key.value
|
||||
response_headers.update(key.metadata)
|
||||
response_headers.update(key.response_dict)
|
||||
return 200, response_headers, key.value
|
||||
|
||||
def _key_response_put(self, request, body, bucket_name, query, key_name, headers):
|
||||
response_headers = {}
|
||||
if query.get('uploadId') and query.get('partNumber'):
|
||||
upload_id = query['uploadId'][0]
|
||||
part_number = int(query['partNumber'][0])
|
||||
@ -501,8 +506,8 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
key = self.backend.set_part(
|
||||
bucket_name, upload_id, part_number, body)
|
||||
response = ""
|
||||
headers.update(key.response_dict)
|
||||
return 200, headers, response
|
||||
response_headers.update(key.response_dict)
|
||||
return 200, response_headers, response
|
||||
|
||||
storage_class = request.headers.get('x-amz-storage-class', 'STANDARD')
|
||||
acl = self._acl_from_headers(request.headers)
|
||||
@ -511,7 +516,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
key = self.backend.get_key(bucket_name, key_name)
|
||||
# TODO: Support the XML-based ACL format
|
||||
key.set_acl(acl)
|
||||
return 200, headers, ""
|
||||
return 200, response_headers, ""
|
||||
|
||||
if 'x-amz-copy-source' in request.headers:
|
||||
# Copy key
|
||||
@ -526,8 +531,8 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
metadata = metadata_from_headers(request.headers)
|
||||
new_key.set_metadata(metadata, replace=True)
|
||||
template = self.response_template(S3_OBJECT_COPY_RESPONSE)
|
||||
headers.update(new_key.response_dict)
|
||||
return 200, headers, template.render(key=new_key)
|
||||
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:
|
||||
@ -546,18 +551,19 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
new_key.set_acl(acl)
|
||||
|
||||
template = self.response_template(S3_OBJECT_RESPONSE)
|
||||
headers.update(new_key.response_dict)
|
||||
return 200, headers, template.render(key=new_key)
|
||||
response_headers.update(new_key.response_dict)
|
||||
return 200, response_headers, template.render(key=new_key)
|
||||
|
||||
def _key_response_head(self, bucket_name, query, key_name, headers):
|
||||
response_headers = {}
|
||||
version_id = query.get('versionId', [None])[0]
|
||||
key = self.backend.get_key(bucket_name, key_name, version_id=version_id)
|
||||
if key:
|
||||
headers.update(key.metadata)
|
||||
headers.update(key.response_dict)
|
||||
return 200, headers, ""
|
||||
response_headers.update(key.metadata)
|
||||
response_headers.update(key.response_dict)
|
||||
return 200, response_headers, ""
|
||||
else:
|
||||
return 404, headers, ""
|
||||
return 404, response_headers, ""
|
||||
|
||||
def _acl_from_headers(self, headers):
|
||||
canned_acl = headers.get('x-amz-acl', '')
|
||||
@ -595,10 +601,10 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
if query.get('uploadId'):
|
||||
upload_id = query['uploadId'][0]
|
||||
self.backend.cancel_multipart(bucket_name, upload_id)
|
||||
return 204, headers, ""
|
||||
return 204, {}, ""
|
||||
self.backend.delete_key(bucket_name, key_name)
|
||||
template = self.response_template(S3_DELETE_OBJECT_SUCCESS)
|
||||
return 204, headers, template.render()
|
||||
return 204, {}, template.render()
|
||||
|
||||
def _complete_multipart_body(self, body):
|
||||
ps = minidom.parseString(body).getElementsByTagName('Part')
|
||||
@ -620,7 +626,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
key_name=key_name,
|
||||
upload_id=multipart.id,
|
||||
)
|
||||
return 200, headers, response
|
||||
return 200, {}, response
|
||||
|
||||
if query.get('uploadId'):
|
||||
body = self._complete_multipart_body(body)
|
||||
@ -640,7 +646,7 @@ class ResponseObject(_TemplateEnvironmentMixin):
|
||||
if key.expiry_date is not None:
|
||||
r = 200
|
||||
key.restore(int(days))
|
||||
return r, headers, ""
|
||||
return r, {}, ""
|
||||
else:
|
||||
raise NotImplementedError("Method POST had only been implemented for multipart uploads and restore operations, so far")
|
||||
|
||||
|
@ -16,7 +16,7 @@ class SWFResponse(BaseResponse):
|
||||
# SWF parameters are passed through a JSON body, so let's ease retrieval
|
||||
@property
|
||||
def _params(self):
|
||||
return json.loads(self.body.decode("utf-8"))
|
||||
return json.loads(self.body)
|
||||
|
||||
def _check_int(self, parameter):
|
||||
if not isinstance(parameter, int):
|
||||
|
@ -70,7 +70,7 @@ def test_publish_to_http():
|
||||
|
||||
last_request = responses.calls[-1].request
|
||||
last_request.method.should.equal("POST")
|
||||
parse_qs(last_request.body.decode('utf-8')).should.equal({
|
||||
parse_qs(last_request.body).should.equal({
|
||||
"Type": ["Notification"],
|
||||
"MessageId": [message_id],
|
||||
"TopicArn": ["arn:aws:sns:{0}:123456789012:some-topic".format(conn.region.name)],
|
||||
|
@ -75,7 +75,7 @@ def test_publish_to_http():
|
||||
|
||||
last_request = responses.calls[-2].request
|
||||
last_request.method.should.equal("POST")
|
||||
parse_qs(last_request.body.decode('utf-8')).should.equal({
|
||||
parse_qs(last_request.body).should.equal({
|
||||
"Type": ["Notification"],
|
||||
"MessageId": [message_id],
|
||||
"TopicArn": ["arn:aws:sns:{0}:123456789012:some-topic".format(conn._client_config.region_name)],
|
||||
|
Loading…
Reference in New Issue
Block a user