Skip to content

Commit abf21c9

Browse files
authored
fix(apigateway): CORS response body has unexpected space (#27219)
Because of the way Velocity templates are parsed, the space just before `#end` in the original template was emitted literally instead of swallowed. This caused the `OPTIONS` response to contain a single space (`" "`), which makes some validation tools reject the response as invalid. Rewrite the Velocity template to a syntax we know doesn't cause that space to be emitted. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 7d02e5e commit abf21c9

File tree

10 files changed

+67
-26
lines changed

10 files changed

+67
-26
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors-allow-multiple-origins.js.snapshot/manifest.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
"environment": "aws://unknown-account/unknown-region",
1515
"properties": {
1616
"templateFile": "stack-cors-allow-multiple-origins.template.json",
17+
"terminationProtection": false,
1718
"validateOnSynth": false,
1819
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
1920
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
20-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/0cc1681b59d7456fa47ee61cb91884542f825e1d36afb4b442a57bf959e4d742.json",
21+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/10b38de28f6f291a0a2fe437096ce3ea526ffeb14c593b034d0df5e8452cde82.json",
2122
"requiresBootstrapStackVersion": 6,
2223
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2324
"additionalDependencies": [
@@ -42,7 +43,7 @@
4243
"/stack-cors-allow-multiple-origins/cors-api-test/Deployment/Resource": [
4344
{
4445
"type": "aws:cdk:logicalId",
45-
"data": "corsapitestDeployment2BF1633Ad72428c37c88b8c23ef39eebb5b7e9fd"
46+
"data": "corsapitestDeployment2BF1633A506e17bacbb92c0f9e65d8c89b158b9c"
4647
}
4748
],
4849
"/stack-cors-allow-multiple-origins/cors-api-test/DeploymentStage.prod/Resource": [
@@ -116,6 +117,15 @@
116117
"type": "aws:cdk:logicalId",
117118
"data": "CheckBootstrapVersion"
118119
}
120+
],
121+
"corsapitestDeployment2BF1633Ad72428c37c88b8c23ef39eebb5b7e9fd": [
122+
{
123+
"type": "aws:cdk:logicalId",
124+
"data": "corsapitestDeployment2BF1633Ad72428c37c88b8c23ef39eebb5b7e9fd",
125+
"trace": [
126+
"!!DESTRUCTIVE_CHANGES: WILL_DESTROY"
127+
]
128+
}
119129
]
120130
},
121131
"displayName": "stack-cors-allow-multiple-origins"
@@ -133,6 +143,7 @@
133143
"environment": "aws://unknown-account/unknown-region",
134144
"properties": {
135145
"templateFile": "integcorsallowmultipleoriginsDefaultTestDeployAssertEBF0A1B1.template.json",
146+
"terminationProtection": false,
136147
"validateOnSynth": false,
137148
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
138149
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors-allow-multiple-origins.js.snapshot/stack-cors-allow-multiple-origins.assets.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
}
1515
}
1616
},
17-
"0cc1681b59d7456fa47ee61cb91884542f825e1d36afb4b442a57bf959e4d742": {
17+
"10b38de28f6f291a0a2fe437096ce3ea526ffeb14c593b034d0df5e8452cde82": {
1818
"source": {
1919
"path": "stack-cors-allow-multiple-origins.template.json",
2020
"packaging": "file"
2121
},
2222
"destinations": {
2323
"current_account-current_region": {
2424
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
25-
"objectKey": "0cc1681b59d7456fa47ee61cb91884542f825e1d36afb4b442a57bf959e4d742.json",
25+
"objectKey": "10b38de28f6f291a0a2fe437096ce3ea526ffeb14c593b034d0df5e8452cde82.json",
2626
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
2727
}
2828
}

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors-allow-multiple-origins.js.snapshot/stack-cors-allow-multiple-origins.template.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Name": "cors-api-test"
77
}
88
},
9-
"corsapitestDeployment2BF1633Ad72428c37c88b8c23ef39eebb5b7e9fd": {
9+
"corsapitestDeployment2BF1633A506e17bacbb92c0f9e65d8c89b158b9c": {
1010
"Type": "AWS::ApiGateway::Deployment",
1111
"Properties": {
1212
"Description": "Automatically created by the RestApi construct",
@@ -25,7 +25,7 @@
2525
"Type": "AWS::ApiGateway::Stage",
2626
"Properties": {
2727
"DeploymentId": {
28-
"Ref": "corsapitestDeployment2BF1633Ad72428c37c88b8c23ef39eebb5b7e9fd"
28+
"Ref": "corsapitestDeployment2BF1633A506e17bacbb92c0f9e65d8c89b158b9c"
2929
},
3030
"RestApiId": {
3131
"Ref": "corsapitest8682546E"
@@ -49,7 +49,7 @@
4949
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
5050
},
5151
"ResponseTemplates": {
52-
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
52+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\")\n #set($origin = $input.params().header.get(\"origin\"))\n#end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
5353
},
5454
"StatusCode": "204"
5555
}
@@ -112,7 +112,7 @@
112112
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
113113
},
114114
"ResponseTemplates": {
115-
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
115+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\")\n #set($origin = $input.params().header.get(\"origin\"))\n#end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
116116
},
117117
"StatusCode": "204"
118118
}

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors-allow-multiple-origins.js.snapshot/tree.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
"aws:cdk:cloudformation:type": "AWS::ApiGateway::Stage",
6565
"aws:cdk:cloudformation:props": {
6666
"deploymentId": {
67-
"Ref": "corsapitestDeployment2BF1633Ad72428c37c88b8c23ef39eebb5b7e9fd"
67+
"Ref": "corsapitestDeployment2BF1633A506e17bacbb92c0f9e65d8c89b158b9c"
6868
},
6969
"restApiId": {
7070
"Ref": "corsapitest8682546E"
@@ -123,7 +123,7 @@
123123
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
124124
},
125125
"responseTemplates": {
126-
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
126+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\")\n #set($origin = $input.params().header.get(\"origin\"))\n#end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
127127
}
128128
}
129129
]
@@ -216,7 +216,7 @@
216216
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
217217
},
218218
"responseTemplates": {
219-
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
219+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\")\n #set($origin = $input.params().header.get(\"origin\"))\n#end\n#if($origin == \"https://twitch.tv\" || $origin == \"https://aws.amazon.com\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
220220
}
221221
}
222222
]
@@ -576,7 +576,7 @@
576576
"path": "integ-cors-allow-multiple-origins/DefaultTest/Default",
577577
"constructInfo": {
578578
"fqn": "constructs.Construct",
579-
"version": "10.2.69"
579+
"version": "10.2.70"
580580
}
581581
},
582582
"DeployAssert": {
@@ -622,7 +622,7 @@
622622
"path": "Tree",
623623
"constructInfo": {
624624
"fqn": "constructs.Construct",
625-
"version": "10.2.69"
625+
"version": "10.2.70"
626626
}
627627
}
628628
},

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors.js.snapshot/cors-twitch-test.assets.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
}
1515
}
1616
},
17-
"2f8b518aaca6753a8d9097bb7f4c058c8e83ebed2d2446f593695bb69f478fc3": {
17+
"3b86b43c1a293038e6b507b773f348d699167e46c088fe6ed4b1ae400ce17192": {
1818
"source": {
1919
"path": "cors-twitch-test.template.json",
2020
"packaging": "file"
2121
},
2222
"destinations": {
2323
"current_account-current_region": {
2424
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
25-
"objectKey": "2f8b518aaca6753a8d9097bb7f4c058c8e83ebed2d2446f593695bb69f478fc3.json",
25+
"objectKey": "3b86b43c1a293038e6b507b773f348d699167e46c088fe6ed4b1ae400ce17192.json",
2626
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
2727
}
2828
}

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors.js.snapshot/cors-twitch-test.template.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"UpdateReplacePolicy": "Retain",
5656
"DeletionPolicy": "Retain"
5757
},
58-
"corsapitestDeployment2BF1633Adc24ac182461aecc920a8724663ce2a1": {
58+
"corsapitestDeployment2BF1633A72d0197fd6797ee251232efbdce56b8a": {
5959
"Type": "AWS::ApiGateway::Deployment",
6060
"Properties": {
6161
"Description": "Automatically created by the RestApi construct",
@@ -75,7 +75,7 @@
7575
"Type": "AWS::ApiGateway::Stage",
7676
"Properties": {
7777
"DeploymentId": {
78-
"Ref": "corsapitestDeployment2BF1633Adc24ac182461aecc920a8724663ce2a1"
78+
"Ref": "corsapitestDeployment2BF1633A72d0197fd6797ee251232efbdce56b8a"
7979
},
8080
"RestApiId": {
8181
"Ref": "corsapitest8682546E"
@@ -471,7 +471,7 @@
471471
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
472472
},
473473
"ResponseTemplates": {
474-
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin == \"https://www.test-cors.org\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
474+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\")\n #set($origin = $input.params().header.get(\"origin\"))\n#end\n#if($origin == \"https://www.test-cors.org\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
475475
},
476476
"StatusCode": "204"
477477
}

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors.js.snapshot/manifest.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
"environment": "aws://unknown-account/unknown-region",
1515
"properties": {
1616
"templateFile": "cors-twitch-test.template.json",
17+
"terminationProtection": false,
1718
"validateOnSynth": false,
1819
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
1920
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
20-
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/2f8b518aaca6753a8d9097bb7f4c058c8e83ebed2d2446f593695bb69f478fc3.json",
21+
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3b86b43c1a293038e6b507b773f348d699167e46c088fe6ed4b1ae400ce17192.json",
2122
"requiresBootstrapStackVersion": 6,
2223
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
2324
"additionalDependencies": [
@@ -54,7 +55,7 @@
5455
"/cors-twitch-test/cors-api-test/Deployment/Resource": [
5556
{
5657
"type": "aws:cdk:logicalId",
57-
"data": "corsapitestDeployment2BF1633Adc24ac182461aecc920a8724663ce2a1"
58+
"data": "corsapitestDeployment2BF1633A72d0197fd6797ee251232efbdce56b8a"
5859
}
5960
],
6061
"/cors-twitch-test/cors-api-test/DeploymentStage.prod/Resource": [
@@ -158,6 +159,15 @@
158159
"type": "aws:cdk:logicalId",
159160
"data": "CheckBootstrapVersion"
160161
}
162+
],
163+
"corsapitestDeployment2BF1633Adc24ac182461aecc920a8724663ce2a1": [
164+
{
165+
"type": "aws:cdk:logicalId",
166+
"data": "corsapitestDeployment2BF1633Adc24ac182461aecc920a8724663ce2a1",
167+
"trace": [
168+
"!!DESTRUCTIVE_CHANGES: WILL_DESTROY"
169+
]
170+
}
161171
]
162172
},
163173
"displayName": "cors-twitch-test"
@@ -175,6 +185,7 @@
175185
"environment": "aws://unknown-account/unknown-region",
176186
"properties": {
177187
"templateFile": "corsDefaultTestDeployAssert5CF8F851.template.json",
188+
"terminationProtection": false,
178189
"validateOnSynth": false,
179190
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
180191
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.cors.js.snapshot/tree.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
"aws:cdk:cloudformation:type": "AWS::ApiGateway::Stage",
141141
"aws:cdk:cloudformation:props": {
142142
"deploymentId": {
143-
"Ref": "corsapitestDeployment2BF1633Adc24ac182461aecc920a8724663ce2a1"
143+
"Ref": "corsapitestDeployment2BF1633A72d0197fd6797ee251232efbdce56b8a"
144144
},
145145
"restApiId": {
146146
"Ref": "corsapitest8682546E"
@@ -682,7 +682,7 @@
682682
"method.response.header.Access-Control-Allow-Methods": "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'"
683683
},
684684
"responseTemplates": {
685-
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\") #set($origin = $input.params().header.get(\"origin\")) #end\n#if($origin == \"https://www.test-cors.org\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
685+
"application/json": "#set($origin = $input.params().header.get(\"Origin\"))\n#if($origin == \"\")\n #set($origin = $input.params().header.get(\"origin\"))\n#end\n#if($origin == \"https://www.test-cors.org\")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end"
686686
}
687687
}
688688
]

packages/aws-cdk-lib/aws-apigateway/lib/resource.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,8 +317,11 @@ export abstract class ResourceBase extends ResourceConstruct implements IResourc
317317

318318
const template = new Array<string>();
319319

320-
template.push('#set($origin = $input.params().header.get("Origin"))');
321-
template.push('#if($origin == "") #set($origin = $input.params().header.get("origin")) #end');
320+
template.push(
321+
'#set($origin = $input.params().header.get("Origin"))',
322+
'#if($origin == "")',
323+
' #set($origin = $input.params().header.get("origin"))',
324+
'#end');
322325

323326
const condition = origins.map(o => `$origin == "${o}"`).join(' || ');
324327

packages/aws-cdk-lib/aws-apigateway/test/cors.test.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,15 @@ describe('cors', () => {
290290
'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'",
291291
},
292292
ResponseTemplates: {
293-
'application/json': '#set($origin = $input.params().header.get("Origin"))\n#if($origin == "") #set($origin = $input.params().header.get("origin")) #end\n#if($origin == "https://amazon.com" || $origin == "https://aws.amazon.com")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end',
293+
'application/json': [
294+
'#set($origin = $input.params().header.get("Origin"))',
295+
'#if($origin == "")',
296+
' #set($origin = $input.params().header.get("origin"))',
297+
'#end',
298+
'#if($origin == "https://amazon.com" || $origin == "https://aws.amazon.com")',
299+
' #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)',
300+
'#end',
301+
].join('\n'),
294302
},
295303
StatusCode: '204',
296304
},
@@ -688,7 +696,15 @@ describe('cors', () => {
688696
'method.response.header.Access-Control-Allow-Methods': "'OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD'",
689697
},
690698
ResponseTemplates: {
691-
'application/json': '#set($origin = $input.params().header.get("Origin"))\n#if($origin == "") #set($origin = $input.params().header.get("origin")) #end\n#if($origin == "https://twitch.tv")\n #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)\n#end',
699+
'application/json': [
700+
'#set($origin = $input.params().header.get("Origin"))',
701+
'#if($origin == "")',
702+
' #set($origin = $input.params().header.get("origin"))',
703+
'#end',
704+
'#if($origin == "https://twitch.tv")',
705+
' #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin)',
706+
'#end',
707+
].join('\n'),
692708
},
693709
StatusCode: '204',
694710
},

0 commit comments

Comments
 (0)