Skip to content

Commit 545de32

Browse files
committed
Version 2.1 - Added CORS support and period (.) to bucket constraint
1 parent bf53df3 commit 545de32

File tree

2 files changed

+62
-35
lines changed

2 files changed

+62
-35
lines changed

deployment/serverless-image-handler.template

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"ConstraintDescription": "Must be a valid S3 Bucket.",
1010
"MinLength": "1",
1111
"MaxLength": "64",
12-
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9-]*"
12+
"AllowedPattern": "[a-zA-Z][a-zA-Z0-9-.]*"
1313
},
1414
"OriginS3BucketRegion": {
1515
"Description": "S3 bucket Region that will source your images.",
@@ -32,6 +32,20 @@
3232
"us-west-2"
3333
]
3434
},
35+
"EnableCors": {
36+
"Description": "Will this API require Cross-Origin Resource Sharing (CORS) support?",
37+
"Default": "No",
38+
"Type": "String",
39+
"AllowedValues": [
40+
"Yes",
41+
"No"
42+
]
43+
},
44+
"CorsOrig": {
45+
"Description": "This value will be returned by the API in the Access-Control-Allow-Origin header. A star (*) value will support any origin. We recommend specifying a specific origin (e.g. http://example.domain) to restrict cross-site access to your API.",
46+
"Default": "*",
47+
"Type": "String"
48+
},
3549
"LambdaLogRetention": {
3650
"Description": "Retain Lambda CloudWatch Logs by days.",
3751
"Type": "Number",
@@ -63,7 +77,7 @@
6377
"ParameterGroups" : [
6478
{
6579
"Label" : { "default":"Image Handler API Configuration" },
66-
"Parameters" : [ "OriginS3Bucket", "OriginS3BucketRegion", "LambdaLogRetention" ]
80+
"Parameters" : [ "OriginS3Bucket", "OriginS3BucketRegion", "EnableCors", "CorsOrig","LambdaLogRetention" ]
6781
},
6882
{
6983
"Label" : { "default":"Image Handler UI Configuration" },
@@ -73,6 +87,8 @@
7387
"ParameterLabels" : {
7488
"OriginS3Bucket" : { "default" : "Origin S3 Bucket" },
7589
"OriginS3BucketRegion" : { "default" : "Origin S3 Bucket Region" },
90+
"EnableCors" : { "default" : "Enable CORS?" },
91+
"CorsOrig" : { "default" : "CORS Origin" },
7692
"LambdaLogRetention" : { "default" : "Lambda Log Retention" },
7793
"DeployUI" : { "default" : "Deploy UI?" },
7894
"UIDestPrefix" : { "default" : "UI Prefix" },
@@ -260,6 +276,8 @@
260276
},
261277
"TC_AWS_REGION":{ "Ref": "OriginS3BucketRegion" },
262278
"TC_AWS_STORAGE_BUCKET":{ "Ref": "OriginS3Bucket" },
279+
"ENABLE_CORS":{ "Ref" : "EnableCors"},
280+
"CORS_ORIGIN":{ "Ref" : "CorsOrig"},
263281
"SEND_ANONYMOUS_DATA":{ "Fn::FindInMap" : [ "Send", "AnonymousUsage", "Data"]},
264282
"UUID":{"Fn::GetAtt": ["CreateUniqueID", "UUID"]},
265283
"LOG_LEVEL":"INFO"
@@ -608,14 +626,6 @@
608626
}
609627
},
610628
"Outputs": {
611-
"CloudFrontURL": {
612-
"Description": "URL for new CloudFront distribution",
613-
"Value": { "Fn::Sub": [ "https://${Domain}", { "Domain": {"Fn::GetAtt": ["ImageHandlerDistribution", "DomainName"]}} ]}
614-
},
615-
"CloudFrontSampleRequest": {
616-
"Description": "Sample URL calling origin image key through CloudFront",
617-
"Value": { "Fn::Sub": [ "https://${Domain}/fit-in/100x100/image-name.jpg", { "Domain": {"Fn::GetAtt": ["ImageHandlerDistribution", "DomainName"]}} ]}
618-
},
619629
"SolutionUI": {
620630
"Description": "If enabled, the URL for the UI.",
621631
"Value": { "Fn::Sub": [
@@ -624,6 +634,22 @@
624634
"Bucket": { "Ref" : "OriginS3Bucket"},
625635
"Prefix": { "Ref" : "UIDestPrefix" } }
626636
] }
637+
},
638+
"CloudFrontURL": {
639+
"Description": "URL for new CloudFront distribution",
640+
"Value": { "Fn::Sub": [ "https://${Domain}", { "Domain": {"Fn::GetAtt": ["ImageHandlerDistribution", "DomainName"]}} ]}
641+
},
642+
"CloudFrontSampleRequest": {
643+
"Description": "Sample URL calling origin image key through CloudFront",
644+
"Value": { "Fn::Sub": [ "https://${Domain}/fit-in/100x100/image-name.jpg", { "Domain": {"Fn::GetAtt": ["ImageHandlerDistribution", "DomainName"]}} ]}
645+
},
646+
"CorsEnabled": {
647+
"Description": "Was CORS support enabled?",
648+
"Value": { "Ref" : "EnableCors"}
649+
},
650+
"CorsOrigin": {
651+
"Description": "If enabled, allow CORS from this origin.",
652+
"Value": { "Ref" : "CorsOrig"}
627653
}
628654
}
629655
}

source/image-handler/lambda_function.py

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,29 @@ def response_formater(status_code='400',
5151
expires='',
5252
etag='',
5353
date=''):
54-
if int(status_code) != 200:
55-
return {
56-
'statusCode': status_code,
57-
'body': json.dumps(body),
58-
'headers': {
59-
'Cache-Control': cache_control,
60-
'Content-Type': content_type
61-
}
62-
}
63-
else:
64-
return {
65-
'statusCode': status_code,
66-
'body': body,
67-
'isBase64Encoded': 'true',
68-
'headers': {
69-
'Content-Type': content_type,
70-
'Expires': expires,
71-
'Etag': etag,
72-
'Cache-Control': cache_control,
73-
'Date': date,
74-
},
54+
55+
api_response = {
56+
'statusCode': status_code,
57+
'headers': {
58+
'Content-Type': content_type
7559
}
60+
}
7661

62+
if str(os.environ.get('ENABLE_CORS')).upper() == "YES":
63+
api_response['headers']['Access-Control-Allow-Origin'] = os.environ.get('CORS_ORIGIN')
64+
65+
if int(status_code) != 200:
66+
api_response['body'] = json.dumps(body)
67+
api_response['Cache-Control'] = cache_control
68+
else:
69+
api_response['body'] = body
70+
api_response['isBase64Encoded'] = 'true'
71+
api_response['headers']['Expires'] = expires
72+
api_response['headers']['Etag'] = etag
73+
api_response['headers']['Cache-Control'] = cache_control
74+
api_response['headers']['Date'] = date
75+
logging.debug(api_response)
76+
return api_response
7777

7878
def run_server(application, context):
7979
server = HTTPServer(application)
@@ -170,12 +170,13 @@ def call_thumbor(request):
170170
)
171171
restart_server()
172172
return response_formater(status_code='502')
173-
if config.ALLOW_UNSAFE_URL:
174-
http_path = '/unsafe' + request['path']
175-
else:
176-
http_path = request['path']
173+
http_path = request['path']
177174
if str(os.environ.get('REWRITE_ENABLED')).upper() == 'YES':
178175
http_path = lambda_rewrite.match_patterns(http_path)
176+
if config.ALLOW_UNSAFE_URL:
177+
http_path = '/unsafe' + http_path
178+
else:
179+
http_path = http_path
179180
response = session.get(unix_path + http_path)
180181
if response.status_code != 200:
181182
return response_formater(status_code=response.status_code)

0 commit comments

Comments
 (0)