diff --git a/packages/@aws-cdk/aws-cloudfront/README.md b/packages/@aws-cdk/aws-cloudfront/README.md index b0ae2f6f79ba3..04488d3670742 100644 --- a/packages/@aws-cdk/aws-cloudfront/README.md +++ b/packages/@aws-cdk/aws-cloudfront/README.md @@ -80,4 +80,26 @@ new cloudfront.CloudFrontWebDistribution(stack, 'MyDistribution', { //... geoRestriction: GeoRestriction.whitelist('US', 'UK') }); -``` \ No newline at end of file +``` + +### Connection behaviors between CloudFront and your origin. + +CloudFront provides you even more control over the connection behaviors between CloudFront and your origin. You can now configure the number of connection attempts CloudFront will make to your origin and the origin connection timeout for each attempt. + +See [Origin Connection Attempts](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#origin-connection-attempts) + +See [Origin Connection Timeout](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#origin-connection-timeout) + +Example usage: + +```ts +const distribution = new CloudFrontWebDistribution(this, 'MyDistribution', { + originConfigs: [ + { + ..., + connectionAttempts: 3, + connectionTimeout: cdk.Duration.seconds(10), + } + ] +}); +``` diff --git a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts index ab5eda0eb0834..f6c9c0fe89019 100644 --- a/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts +++ b/packages/@aws-cdk/aws-cloudfront/lib/web_distribution.ts @@ -140,15 +140,31 @@ export interface LoggingConfiguration { * One or the other must be passed, and it is invalid to pass both in the same SourceConfiguration. */ export interface SourceConfiguration { + /** + * The number of times that CloudFront attempts to connect to the origin. + * You can specify 1, 2, or 3 as the number of attempts. + * + * @default 3 + */ + readonly connectionAttempts?: number; + + /** + * The number of seconds that CloudFront waits when trying to establish a connection to the origin. + * You can specify a number of seconds between 1 and 10 (inclusive). + * + * @default cdk.Duration.seconds(10) + */ + readonly connectionTimeout?: cdk.Duration; + /** * An s3 origin source - if you're using s3 for your assets */ - readonly s3OriginSource?: S3OriginConfig + readonly s3OriginSource?: S3OriginConfig; /** * A custom origin source - for all non-s3 sources. */ - readonly customOriginSource?: CustomOriginConfig, + readonly customOriginSource?: CustomOriginConfig; /** * The behaviors associated with this source. @@ -161,7 +177,7 @@ export interface SourceConfiguration { * * @default / */ - readonly originPath?: string, + readonly originPath?: string; /** * Any additional headers to pass to the origin @@ -771,6 +787,16 @@ export class CloudFrontWebDistribution extends cdk.Construct implements IDistrib } } + const connectionAttempts = originConfig.connectionAttempts ?? 3; + if (connectionAttempts < 1 || 3 < connectionAttempts || !Number.isInteger(connectionAttempts)) { + throw new Error('connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + } + + const connectionTimeout = (originConfig.connectionTimeout || cdk.Duration.seconds(10)).toSeconds(); + if (connectionTimeout < 1 || 10 < connectionTimeout || !Number.isInteger(connectionTimeout)) { + throw new Error('connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + } + const originProperty: CfnDistribution.OriginProperty = { id: originId, domainName: originConfig.s3OriginSource @@ -791,6 +817,8 @@ export class CloudFrontWebDistribution extends cdk.Construct implements IDistrib originSslProtocols: originConfig.customOriginSource.allowedOriginSSLVersions || [OriginSslPolicy.TLS_V1_2], } : undefined, + connectionAttempts, + connectionTimeout, }; for (const behavior of originConfig.behaviors) { diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json index 70780cca41033..36a334898a57f 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-bucket-logging.expected.json @@ -44,6 +44,8 @@ }, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, @@ -114,6 +116,8 @@ }, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom-s3.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom-s3.expected.json index 954b13e1edc67..7699faf6df792 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom-s3.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom-s3.expected.json @@ -72,6 +72,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom.expected.json index 92071bb9ef237..5943d0d822d3c 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-custom.expected.json @@ -29,6 +29,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-empty-root.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-empty-root.expected.json index a5298a4968004..9b20011d6a9a1 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-empty-root.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-empty-root.expected.json @@ -29,6 +29,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-geo-restrictions.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-geo-restrictions.expected.json index 25ae7addfd317..9307879bca924 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-geo-restrictions.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-geo-restrictions.expected.json @@ -34,6 +34,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Bucket83908E77", diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-ipv6-disabled.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-ipv6-disabled.expected.json index 5ffa5da872430..30bc881df48f3 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-ipv6-disabled.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-ipv6-disabled.expected.json @@ -34,6 +34,8 @@ "IPV6Enabled": false, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Bucket83908E77", diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json index cce226bd3a090..eb45a5dd3192d 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-lambda-association.expected.json @@ -107,6 +107,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Bucket83908E77", diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json index b1ddafe584cf3..8f6357e72272e 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-s3.expected.json @@ -102,6 +102,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Bucket83908E77", diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-security-policy.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-security-policy.expected.json index 861887bd54f48..068f2e3492856 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-security-policy.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront-security-policy.expected.json @@ -32,6 +32,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, diff --git a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront.expected.json b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront.expected.json index a5f3615733d82..acadf8baf6866 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront.expected.json +++ b/packages/@aws-cdk/aws-cloudfront/test/integ.cloudfront.expected.json @@ -34,6 +34,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Bucket83908E77", diff --git a/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts b/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts index 39366da64117d..6aeeea31c4cf9 100644 --- a/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts +++ b/packages/@aws-cdk/aws-cloudfront/test/test.basic.ts @@ -82,6 +82,8 @@ export = { 'TLSv1.2', ], }, + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': 'myorigin.com', 'Id': 'origin1', 'OriginCustomHeaders': [ @@ -139,6 +141,8 @@ export = { 'DefaultRootObject': 'index.html', 'Origins': [ { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': { 'Fn::GetAtt': [ 'Bucket83908E77', @@ -215,6 +219,8 @@ export = { 'DefaultRootObject': 'index.html', 'Origins': [ { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': { 'Fn::GetAtt': [ 'Bucket83908E77', @@ -294,6 +300,8 @@ export = { 'DefaultRootObject': 'index.html', 'Origins': [ { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': { 'Fn::GetAtt': [ 'Bucket83908E77', @@ -370,6 +378,8 @@ export = { 'DefaultRootObject': 'index.html', 'Origins': [ { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': { 'Fn::GetAtt': [ 'Bucket83908E77', @@ -905,6 +915,8 @@ export = { 'DefaultRootObject': 'index.html', 'Origins': [ { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': { 'Fn::GetAtt': [ 'Bucket83908E77', @@ -979,6 +991,8 @@ export = { 'DefaultRootObject': 'index.html', 'Origins': [ { + 'ConnectionAttempts': 3, + 'ConnectionTimeout': 10, 'DomainName': { 'Fn::GetAtt': [ 'Bucket83908E77', @@ -1053,4 +1067,167 @@ export = { }, }, }, + + 'Connection behaviors between CloudFront and your origin': { + 'success': { + 'connectionAttempts = 1'(test: Test) { + const stack = new cdk.Stack(); + test.doesNotThrow(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionAttempts: 1, + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + test.done(); + }, + '3 = connectionAttempts'(test: Test) { + const stack = new cdk.Stack(); + test.doesNotThrow(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionAttempts: 3, + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + test.done(); + }, + 'connectionTimeout = 1'(test: Test) { + const stack = new cdk.Stack(); + test.doesNotThrow(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionTimeout: cdk.Duration.seconds(1), + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + test.done(); + }, + '10 = connectionTimeout'(test: Test) { + const stack = new cdk.Stack(); + test.doesNotThrow(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionTimeout: cdk.Duration.seconds(10), + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + test.done(); + }, + }, + 'errors': { + 'connectionAttempts = 1.1'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionAttempts: 1.1, + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + test.done(); + }, + 'connectionAttempts = -1'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionAttempts: -1, + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + test.done(); + }, + 'connectionAttempts < 1'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionAttempts: 0, + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + test.done(); + }, + '3 < connectionAttempts'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionAttempts: 4, + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionAttempts: You can specify 1, 2, or 3 as the number of attempts.'); + test.done(); + }, + 'connectionTimeout = 1.1'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionTimeout: cdk.Duration.seconds(1.1), + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + test.done(); + }, + 'connectionTimeout = -1'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionTimeout: cdk.Duration.seconds(-1), + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + test.done(); + }, + 'connectionTimeout < 1'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionTimeout: cdk.Duration.seconds(0), + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + test.done(); + }, + '10 < connectionTimeout'(test: Test) { + const stack = new cdk.Stack(); + test.throws(() => { + new CloudFrontWebDistribution(stack, 'Distribution', { + originConfigs: [{ + behaviors: [{ isDefaultBehavior: true }], + connectionTimeout: cdk.Duration.seconds(11), + customOriginSource: { domainName: 'myorigin.com' }, + }], + }); + }, 'connectionTimeout: You can specify a number of seconds between 1 and 10 (inclusive).'); + test.done(); + }, + }, + }, }; diff --git a/packages/@aws-cdk/aws-route53-targets/test/integ.cloudfront-alias-target.expected.json b/packages/@aws-cdk/aws-route53-targets/test/integ.cloudfront-alias-target.expected.json index 76bd0647bca15..7a91ba087aaab 100644 --- a/packages/@aws-cdk/aws-route53-targets/test/integ.cloudfront-alias-target.expected.json +++ b/packages/@aws-cdk/aws-route53-targets/test/integ.cloudfront-alias-target.expected.json @@ -59,6 +59,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Bucket83908E77", diff --git a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json index e5e0dfe714f00..7563384f9b9f0 100644 --- a/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json +++ b/packages/@aws-cdk/aws-s3-deployment/test/integ.bucket-deployment-cloudfront.expected.json @@ -34,6 +34,8 @@ "IPV6Enabled": true, "Origins": [ { + "ConnectionAttempts": 3, + "ConnectionTimeout": 10, "DomainName": { "Fn::GetAtt": [ "Destination3E3DC043D",