Permalink
Browse files

First working version using proxy+. Works nicely, status codes are fi…

…xed woot - TODO - test binary uploads and responses :[
  • Loading branch information...
Miserlou committed Sep 29, 2016
1 parent b9ce293 commit c8addf5d36c395a1f06badc1153c4c0359f70147
Showing with 126 additions and 120 deletions.
  1. +37 −32 zappa/handler.py
  2. +10 −10 zappa/middleware.py
  3. +32 −25 zappa/wsgi.py
  4. +47 −53 zappa/zappa.py
View
@@ -317,7 +317,7 @@ def handler(self, event, context):
elif event.get('raw_command', None):
raw_command = event['raw_command']
- exec(raw_command)
+ exec(raw_command)
return
# This is a Django management command invocation.
@@ -360,13 +360,13 @@ def handler(self, event, context):
time_start = datetime.datetime.now()
# This is a normal HTTP request
- if event.get('method', None):
+ if event.get('httpMethod', None):
# If we just want to inspect this,
# return this event instead of processing the request
# https://your_api.aws-api.com/?event_echo=true
- event_echo = getattr(settings, "EVENT_ECHO", True)
- if event_echo and 'event_echo' in event['params'].values():
- return {'Content': str(event) + '\n' + str(context), 'Status': 200}
+ # event_echo = getattr(settings, "EVENT_ECHO", True)
+ # if event_echo and 'event_echo' in event['params'].values():
+ # return {'Content': str(event) + '\n' + str(context), 'Status': 200}
if settings.DOMAIN:
# If we're on a domain, we operate normally
@@ -395,36 +395,39 @@ def handler(self, event, context):
# This is the object we're going to return.
# Pack the WSGI response into our special dictionary.
- zappa_returndict = dict(response.headers)
+ zappa_returndict = dict()
- if 'Content' not in zappa_returndict and response.data:
- zappa_returndict['Content'] = response.data
+ if response.data:
+ zappa_returndict['body'] = response.data
- zappa_returndict['Status'] = response.status_code
+ zappa_returndict['statusCode'] = response.status_code
+ zappa_returndict['headers'] = {}
+ for key, value in response.headers:
+ zappa_returndict['headers'][key] = value
# To ensure correct status codes, we need to
# pack the response as a deterministic B64 string and raise it
# as an error to match our APIGW regex.
# The DOCTYPE ensures that the page still renders in the browser.
exception = None
- if response.status_code in ERROR_CODES:
- content = collections.OrderedDict()
- content['http_status'] = response.status_code
- content['content'] = base64.b64encode(response.data.encode('utf-8'))
- exception = json.dumps(content)
- # Internal are changed to become relative redirects
- # so they still work for apps on raw APIGW and on a domain.
- elif 300 <= response.status_code < 400 and hasattr(response, 'Location'):
- # Location is by default relative on Flask. Location is by default
- # absolute on Werkzeug. We can set autocorrect_location_header on
- # the response to False, but it doesn't work. We have to manually
- # remove the host part.
- location = response.location
- hostname = 'https://' + environ['HTTP_HOST']
- if location.startswith(hostname):
- exception = location[len(hostname):]
- else:
- exception = location
+ # if response.status_code in ERROR_CODES:
+ # content = collections.OrderedDict()
+ # content['http_status'] = response.status_code
+ # content['content'] = base64.b64encode(response.data.encode('utf-8'))
+ # exception = json.dumps(content)
+ # # Internal are changed to become relative redirects
+ # # so they still work for apps on raw APIGW and on a domain.
+ # elif 300 <= response.status_code < 400 and hasattr(response, 'Location'):
+ # # Location is by default relative on Flask. Location is by default
+ # # absolute on Werkzeug. We can set autocorrect_location_header on
+ # # the response to False, but it doesn't work. We have to manually
+ # # remove the host part.
+ # location = response.location
+ # hostname = 'https://' + environ['HTTP_HOST']
+ # if location.startswith(hostname):
+ # exception = location[len(hostname):]
+ # else:
+ # exception = location
# Calculate the total response time,
# and log it in the Common Log format.
@@ -434,11 +437,13 @@ def handler(self, event, context):
response.content = response.data
common_log(environ, response, response_time=response_time_ms)
- # Finally, return the response to API Gateway.
- if exception: # pragma: no cover
- raise WSGIException(exception)
- else:
- return zappa_returndict
+ # # Finally, return the response to API Gateway.
+ # if exception: # pragma: no cover
+ # raise WSGIException(exception)
+ # else:
+ #
+
+ return zappa_returndict
except WSGIException as e: # pragma: no cover
raise e
except Exception as e: # pragma: no cover
View
@@ -134,16 +134,16 @@ def encode_response(self, status, headers, exc_info=None):
# If setting cookie on a 301/2,
# return 200 and replace the content with a javascript redirector
- content_type_header_key = [k for k, v in enumerate(new_headers) if v[0] == 'Content-Type']
- if len(content_type_header_key) > 0:
- if "text/html" in new_headers[content_type_header_key[0]][1]:
- if status != '200 OK':
- for key, value in new_headers:
- if key != 'Location':
- continue
- self.redirect_content = REDIRECT_HTML.replace('REDIRECT_ME', value)
- status = '200 OK'
- break
+ # content_type_header_key = [k for k, v in enumerate(new_headers) if v[0] == 'Content-Type']
+ # if len(content_type_header_key) > 0:
+ # if "text/html" in new_headers[content_type_header_key[0]][1]:
+ # if status != '200 OK':
+ # for key, value in new_headers:
+ # if key != 'Location':
+ # continue
+ # self.redirect_content = REDIRECT_HTML.replace('REDIRECT_ME', value)
+ # status = '200 OK'
+ # break
return self.start_response(status, new_headers, exc_info)
View
@@ -13,9 +13,11 @@ def create_wsgi_request(event_info, server_name='zappa', script_name=None,
create and return a valid WSGI request environ.
"""
- method = event_info['method']
- params = event_info['params']
- query = event_info['query']
+ print("MAKING WSGI REQUEST!!!")
+
+ method = event_info['httpMethod']
+ params = event_info['pathParameters']
+ query = event_info['queryStringParameters']
headers = event_info['headers']
# Non-GET data is B64'd through the APIGW.
@@ -31,26 +33,28 @@ def create_wsgi_request(event_info, server_name='zappa', script_name=None,
if canonical != header:
headers[canonical] = headers.pop(header)
- if 'url' in params:
- # new style
- path = '/' + params.get('url') + "/"
- else:
- # old style
- path = "/"
- for key in sorted(params.keys()):
- path = path + params[key] + "/"
-
- # This determines if we should return
- # site.com/resource/ : site.com/resource
- # site.com/resource : site.com/resource
- # vs.
- # site.com/resource/ : site.com/resource/
- # site.com/resource : site.com/resource/
- # If no params are present, keep the slash.
- if not trailing_slash and params.keys():
- path = path[:-1]
-
- query_string = urlencode(query)
+ path = event_info['path']
+
+ # if 'url' in params:
+ # # new style
+ # path = '/' + params.get('url') + "/"
+ # else:
+ # # old style
+ # path = "/"
+ # for key in sorted(params.keys()):
+ # path = path + params[key] + "/"
+
+ # # This determines if we should return
+ # # site.com/resource/ : site.com/resource
+ # # site.com/resource : site.com/resource
+ # # vs.
+ # # site.com/resource/ : site.com/resource/
+ # # site.com/resource : site.com/resource/
+ # # If no params are present, keep the slash.
+ # if not trailing_slash and params.keys():
+ # path = path[:-1]
+
+ query_string = query #$urlencode(query)
x_forwarded_for = headers.get('X-Forwarded-For', '')
if ',' in x_forwarded_for:
@@ -87,8 +91,8 @@ def create_wsgi_request(event_info, server_name='zappa', script_name=None,
# if 'multipart/form-data;' in headers['Content-Type']:
#
# # Unfortunately, this only works for text data,
- # # not binary data. Yet.
- # # See:
+ # # not binary data. Yet.
+ # # See:
# # https://github.com/Miserlou/Zappa/issues/80
# # https://forums.aws.amazon.com/thread.jspa?threadID=231371&tstart=0
# body = base64.b64decode(body)
@@ -107,6 +111,9 @@ def create_wsgi_request(event_info, server_name='zappa', script_name=None,
if script_name in path_info:
environ['PATH_INFO'].replace(script_name, '')
+ print("ENVIRON!!!")
+ print environ
+
return environ
View
@@ -200,13 +200,7 @@ class Zappa(object):
##
http_methods = [
- 'DELETE',
- 'GET',
- 'HEAD',
- 'OPTIONS',
- 'PATCH',
- 'POST',
- 'PUT'
+ 'ANY'
]
parameter_depth = 8
integration_response_codes = [200, 201, 301, 400, 401, 403, 404, 500]
@@ -699,7 +693,7 @@ def create_api_gateway_routes(self, lambda_arn, api_name=None, api_key_required=
self.cf_api_resources.append(resource.title)
resource.RestApiId = troposphere.Ref(restapi)
resource.ParentId = root_id
- resource.PathPart = "{url+}"
+ resource.PathPart = "{proxy+}"
self.cf_template.add_resource(resource)
self.create_and_setup_methods(restapi, resource, lambda_arn, api_key_required,
@@ -726,16 +720,16 @@ def create_and_setup_methods(self, restapi, resource, lambda_arn, api_key_requir
self.cf_template.add_resource(method)
self.cf_api_resources.append(method.title)
- content_mapping_templates = {
- 'application/json': self.cache_param(POST_TEMPLATE_MAPPING),
- 'application/x-www-form-urlencoded': self.cache_param(POST_TEMPLATE_MAPPING),
- 'multipart/form-data': self.cache_param(FORM_ENCODED_TEMPLATE_MAPPING)
- }
- if integration_content_type_aliases:
- for content_type in content_mapping_templates.keys():
- aliases = integration_content_type_aliases.get(content_type, [])
- for alias in aliases:
- content_mapping_templates[alias] = self.cache_param(content_mapping_templates[content_type])
+ # content_mapping_templates = {
+ # 'application/json': self.cache_param(POST_TEMPLATE_MAPPING),
+ # 'application/x-www-form-urlencoded': self.cache_param(POST_TEMPLATE_MAPPING),
+ # 'multipart/form-data': self.cache_param(FORM_ENCODED_TEMPLATE_MAPPING)
+ # }
+ # if integration_content_type_aliases:
+ # for content_type in content_mapping_templates.keys():
+ # aliases = integration_content_type_aliases.get(content_type, [])
+ # for alias in aliases:
+ # content_mapping_templates[alias] = self.cache_param(content_mapping_templates[content_type])
if not self.credentials_arn:
self.get_credentials_arn()
@@ -751,55 +745,55 @@ def create_and_setup_methods(self, restapi, resource, lambda_arn, api_key_requir
integration.IntegrationResponses = []
integration.PassthroughBehavior = 'NEVER'
# integration.RequestParameters = {}
- integration.RequestTemplates = content_mapping_templates
- integration.Type = 'AWS'
+ # integration.RequestTemplates = content_mapping_templates
+ integration.Type = 'AWS_PROXY'
integration.Uri = uri
method.Integration = integration
##
# Method Response
##
- for response_code in self.method_response_codes:
- status_code = str(response_code)
+ # for response_code in self.method_response_codes:
+ # status_code = str(response_code)
- response_parameters = {"method.response.header." + header_type: False for header_type in self.method_header_types}
- response_models = {content_type: 'Empty' for content_type in self.method_content_types}
+ # response_parameters = {"method.response.header." + header_type: False for header_type in self.method_header_types}
+ # response_models = {content_type: 'Empty' for content_type in self.method_content_types}
- response = troposphere.apigateway.MethodResponse()
- response.ResponseModels = response_models
- response.ResponseParameters = response_parameters
- response.StatusCode = status_code
- method.MethodResponses.append(response)
+ # response = troposphere.apigateway.MethodResponse()
+ # response.ResponseModels = response_models
+ # response.ResponseParameters = response_parameters
+ # response.StatusCode = status_code
+ # method.MethodResponses.append(response)
##
# Integration Response
##
- for response in self.integration_response_codes:
- status_code = str(response)
-
- response_parameters = {
- "method.response.header." + header_type: self.cache_param("integration.response.body." + header_type)
- for header_type in self.method_header_types}
-
- # Error code matching RegEx
- # Thanks to @KevinHornschemeier and @jayway
- # for the discussion on this.
- if status_code == '200':
- response_templates = {content_type: self.cache_param(RESPONSE_TEMPLATE) for content_type in self.integration_content_types}
- elif status_code in ['301', '302']:
- response_templates = {content_type: REDIRECT_RESPONSE_TEMPLATE for content_type in self.integration_content_types}
- response_parameters["method.response.header.Location"] = self.cache_param("integration.response.body.errorMessage")
- else:
- response_templates = {content_type: self.cache_param(ERROR_RESPONSE_TEMPLATE) for content_type in self.integration_content_types}
-
- integration_response = troposphere.apigateway.IntegrationResponse()
- integration_response.ResponseParameters = response_parameters
- integration_response.ResponseTemplates = response_templates
- integration_response.SelectionPattern = self.selection_pattern(status_code)
- integration_response.StatusCode = status_code
- integration.IntegrationResponses.append(integration_response)
+ # for response in self.integration_response_codes:
+ # status_code = str(response)
+
+ # response_parameters = {
+ # "method.response.header." + header_type: self.cache_param("integration.response.body." + header_type)
+ # for header_type in self.method_header_types}
+
+ # # Error code matching RegEx
+ # # Thanks to @KevinHornschemeier and @jayway
+ # # for the discussion on this.
+ # if status_code == '200':
+ # response_templates = {content_type: self.cache_param(RESPONSE_TEMPLATE) for content_type in self.integration_content_types}
+ # elif status_code in ['301', '302']:
+ # response_templates = {content_type: REDIRECT_RESPONSE_TEMPLATE for content_type in self.integration_content_types}
+ # response_parameters["method.response.header.Location"] = self.cache_param("integration.response.body.errorMessage")
+ # else:
+ # response_templates = {content_type: self.cache_param(ERROR_RESPONSE_TEMPLATE) for content_type in self.integration_content_types}
+
+ # integration_response = troposphere.apigateway.IntegrationResponse()
+ # integration_response.ResponseParameters = response_parameters
+ # integration_response.ResponseTemplates = response_templates
+ # integration_response.SelectionPattern = self.selection_pattern(status_code)
+ # integration_response.StatusCode = status_code
+ # integration.IntegrationResponses.append(integration_response)
def deploy_api_gateway(self, api_id, stage_name, stage_description="", description="", cache_cluster_enabled=False, cache_cluster_size='0.5', variables=None,
cloudwatch_log_level='OFF', cloudwatch_data_trace=False, cloudwatch_metrics_enabled=False):

0 comments on commit c8addf5

Please sign in to comment.