diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts index 70c9b6a8997f2..b2d48da162667 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/function-url-origin.ts @@ -12,7 +12,8 @@ import { lit } from '../../core/lib/private/literal-string'; export interface FunctionUrlOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront waits for a response from the origin. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the origin response timeout quota, which is + * adjustable, so the effective maximum depends on the target account. * * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. @@ -23,10 +24,11 @@ export interface FunctionUrlOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront persists its connection to the origin. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the keep-alive timeout per origin quota, + * which is adjustable, so the effective maximum depends on the target account. * - * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota - * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. + * The default quota allows up to 300 seconds; higher values require an approved limit increase + * in the target account, and otherwise produce an error at deploy time. * * @default Duration.seconds(5) */ @@ -77,8 +79,8 @@ export class FunctionUrlOrigin extends cloudfront.OriginBase { const domainName = cdk.Fn.select(2, cdk.Fn.split('/', lambdaFunctionUrl.url)); super(domainName, props); - validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); - validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + validateSecondsInRangeOrUndefined('readTimeout', 1, undefined, props.readTimeout); + validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, undefined, props.keepaliveTimeout); this.validateResponseCompletionTimeoutWithReadTimeout(props.responseCompletionTimeout, props.readTimeout); } @@ -109,8 +111,8 @@ class FunctionUrlOriginWithOAC extends cloudfront.OriginBase { this.props = props; - validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); - validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + validateSecondsInRangeOrUndefined('readTimeout', 1, undefined, props.readTimeout); + validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, undefined, props.keepaliveTimeout); } protected renderCustomOriginConfig(): cloudfront.CfnDistribution.CustomOriginConfigProperty | undefined { diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts index d0a42ef5c056f..05ced39c93cc6 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/http-origin.ts @@ -38,7 +38,8 @@ export interface HttpOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront waits for a response from the origin, also known as the origin response timeout. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the origin response timeout quota, which is + * adjustable, so the effective maximum depends on the target account. * * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. @@ -49,10 +50,11 @@ export interface HttpOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront persists its connection to the origin. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the keep-alive timeout per origin quota, + * which is adjustable, so the effective maximum depends on the target account. * - * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota - * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. + * The default quota allows up to 300 seconds; higher values require an approved limit increase + * in the target account, and otherwise produce an error at deploy time. * * @default Duration.seconds(5) */ @@ -75,8 +77,8 @@ export class HttpOrigin extends cloudfront.OriginBase { constructor(domainName: string, private readonly props: HttpOriginProps = {}) { super(domainName, props); - validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); - validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + validateSecondsInRangeOrUndefined('readTimeout', 1, undefined, props.readTimeout); + validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, undefined, props.keepaliveTimeout); this.validateResponseCompletionTimeoutWithReadTimeout(props.responseCompletionTimeout, props.readTimeout); this.validatePortNumber('httpPort', props.httpPort); diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/private/utils.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/private/utils.ts index edf4aaa85fac1..18031472d9e99 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/private/utils.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/private/utils.ts @@ -3,11 +3,16 @@ import { lit } from '../../../core/lib/private/literal-string'; /** * Throws an error if a duration is defined and not an integer number of seconds within a range. + * + * Pass `undefined` for `max` to validate the lower bound only. This is for values whose upper + * bound is an adjustable service quota, so the effective maximum depends on the target account + * and can only be enforced by the service at deploy time. */ -export function validateSecondsInRangeOrUndefined(name: string, min: number, max: number, duration?: cdk.Duration) { +export function validateSecondsInRangeOrUndefined(name: string, min: number, max: number | undefined, duration?: cdk.Duration) { if (duration === undefined) { return; } const value = duration.toSeconds(); - if (!Number.isInteger(value) || value < min || value > max) { - throw new cdk.UnscopedValidationError(lit`InvalidDurationRange`, `${name}: Must be an int between ${min} and ${max} seconds (inclusive); received ${value}.`); + if (!Number.isInteger(value) || value < min || (max !== undefined && value > max)) { + const range = max !== undefined ? `between ${min} and ${max} seconds (inclusive)` : `${min} seconds or greater`; + throw new cdk.UnscopedValidationError(lit`InvalidDurationRange`, `${name}: Must be an int ${range}; received ${value}.`); } } diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts index 03518a532d685..a5160f621841c 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/rest-api-origin.ts @@ -9,7 +9,8 @@ import * as cdk from '../../core'; export interface RestApiOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront waits for a response from the origin, also known as the origin response timeout. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the origin response timeout quota, which is + * adjustable, so the effective maximum depends on the target account. * * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. @@ -20,10 +21,11 @@ export interface RestApiOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront persists its connection to the origin. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the keep-alive timeout per origin quota, + * which is adjustable, so the effective maximum depends on the target account. * - * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota - * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. + * The default quota allows up to 300 seconds; higher values require an approved limit increase + * in the target account, and otherwise produce an error at deploy time. * * @default Duration.seconds(5) */ @@ -43,8 +45,8 @@ export class RestApiOrigin extends cloudfront.OriginBase { ...props, }); - validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); - validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + validateSecondsInRangeOrUndefined('readTimeout', 1, undefined, props.readTimeout); + validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, undefined, props.keepaliveTimeout); this.validateResponseCompletionTimeoutWithReadTimeout(props.responseCompletionTimeout, props.readTimeout); } diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/vpc-origin.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/vpc-origin.ts index 55acf4fd40773..a6b501dc38b2f 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/lib/vpc-origin.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/lib/vpc-origin.ts @@ -18,7 +18,8 @@ export interface VpcOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront waits for a response from the origin, also known as the origin response timeout. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the origin response timeout quota, which is + * adjustable, so the effective maximum depends on the target account. * * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. @@ -29,10 +30,11 @@ export interface VpcOriginProps extends cloudfront.OriginProps { /** * Specifies how long, in seconds, CloudFront persists its connection to the origin. - * The valid range is from 1 to 180 seconds, inclusive. + * The minimum is 1 second. The maximum is governed by the keep-alive timeout per origin quota, + * which is adjustable, so the effective maximum depends on the target account. * - * Note that values over 60 seconds are possible only after a limit increase request for the origin response timeout quota - * has been approved in the target account; otherwise, values over 60 seconds will produce an error at deploy time. + * The default quota allows up to 300 seconds; higher values require an approved limit increase + * in the target account, and otherwise produce an error at deploy time. * * @default Duration.seconds(5) */ @@ -83,8 +85,8 @@ export abstract class VpcOrigin extends cloudfront.OriginBase { protected constructor(domainName: string, protected readonly props: VpcOriginProps) { super(domainName, props); - validateSecondsInRangeOrUndefined('readTimeout', 1, 180, props.readTimeout); - validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, 180, props.keepaliveTimeout); + validateSecondsInRangeOrUndefined('readTimeout', 1, undefined, props.readTimeout); + validateSecondsInRangeOrUndefined('keepaliveTimeout', 1, undefined, props.keepaliveTimeout); } protected renderVpcOriginConfig(): cloudfront.CfnDistribution.VpcOriginConfigProperty | undefined { diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts index 373835feec0d7..7bf0cb12953bc 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/test/http-origin.test.ts @@ -71,20 +71,29 @@ test('renders an example with all available props', () => { test.each([ Duration.seconds(0), +])('validates readTimeout is at least 1 second', (readTimeout) => { + expect(() => { + new HttpOrigin('www.example.com', { + readTimeout, + }); + }).toThrow(`readTimeout: Must be an int 1 seconds or greater; received ${readTimeout.toSeconds()}.`); +}); + +test.each([ Duration.seconds(181), Duration.minutes(5), -])('validates readTimeout is an integer between 1 and 180 seconds - out of bounds', (readTimeout) => { +])('allows readTimeout above the default quota, which the service validates at deploy time', (readTimeout) => { expect(() => { new HttpOrigin('www.example.com', { readTimeout, }); - }).toThrow(`readTimeout: Must be an int between 1 and 180 seconds (inclusive); received ${readTimeout.toSeconds()}.`); + }).not.toThrow(); }); test.each([ Duration.seconds(0.5), Duration.seconds(60.5), -])('validates readTimeout is an integer between 1 and 180 seconds - not an int', (readTimeout) => { +])('validates readTimeout is a whole number of seconds', (readTimeout) => { expect(() => { new HttpOrigin('www.example.com', { readTimeout, @@ -94,20 +103,29 @@ test.each([ test.each([ Duration.seconds(0), +])('validates keepaliveTimeout is at least 1 second', (keepaliveTimeout) => { + expect(() => { + new HttpOrigin('www.example.com', { + keepaliveTimeout, + }); + }).toThrow(`keepaliveTimeout: Must be an int 1 seconds or greater; received ${keepaliveTimeout.toSeconds()}.`); +}); + +test.each([ Duration.seconds(181), Duration.minutes(5), -])('validates keepaliveTimeout is an integer between 1 and 180 seconds - out of bounds', (keepaliveTimeout) => { +])('allows keepaliveTimeout within the default quota, which the service validates at deploy time', (keepaliveTimeout) => { expect(() => { new HttpOrigin('www.example.com', { keepaliveTimeout, }); - }).toThrow(`keepaliveTimeout: Must be an int between 1 and 180 seconds (inclusive); received ${keepaliveTimeout.toSeconds()}.`); + }).not.toThrow(); }); test.each([ Duration.seconds(0.5), Duration.seconds(60.5), -])('validates keepaliveTimeout is an integer between 1 and 180 seconds - not an int', (keepaliveTimeout) => { +])('validates keepaliveTimeout is a whole number of seconds', (keepaliveTimeout) => { expect(() => { new HttpOrigin('www.example.com', { keepaliveTimeout, diff --git a/packages/aws-cdk-lib/aws-cloudfront-origins/test/vpc-origin.test.ts b/packages/aws-cdk-lib/aws-cloudfront-origins/test/vpc-origin.test.ts index a62d18bb6ac81..be43f0042295a 100644 --- a/packages/aws-cdk-lib/aws-cloudfront-origins/test/vpc-origin.test.ts +++ b/packages/aws-cdk-lib/aws-cloudfront-origins/test/vpc-origin.test.ts @@ -206,9 +206,21 @@ test('VPC origin from an imported VpcOrigin resource', () => { test.each([ Duration.seconds(0), +])('VPC origin throws when readTimeout is %s - below the minimum', (readTimeout) => { + // GIVEN + const vpc = new ec2.Vpc(stack, 'Vpc'); + const loadBalancer = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc }); + + // WHEN + expect(() => { + VpcOrigin.withApplicationLoadBalancer(loadBalancer, { readTimeout }); + }).toThrow(`readTimeout: Must be an int 1 seconds or greater; received ${readTimeout.toSeconds()}`); +}); + +test.each([ Duration.seconds(181), Duration.minutes(5), -])('VPC origin throws when readTimeout is %s - out of bounds', (readTimeout) => { +])('VPC origin allows readTimeout of %s above the default quota', (readTimeout) => { // GIVEN const vpc = new ec2.Vpc(stack, 'Vpc'); const loadBalancer = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc }); @@ -216,14 +228,26 @@ test.each([ // WHEN expect(() => { VpcOrigin.withApplicationLoadBalancer(loadBalancer, { readTimeout }); - }).toThrow(`readTimeout: Must be an int between 1 and 180 seconds (inclusive); received ${readTimeout.toSeconds()}`); + }).not.toThrow(); }); test.each([ Duration.seconds(0), +])('VPC origin throws when keepaliveTimeout is %s - below the minimum', (keepaliveTimeout) => { + // GIVEN + const vpc = new ec2.Vpc(stack, 'Vpc'); + const loadBalancer = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc }); + + // WHEN + expect(() => { + VpcOrigin.withApplicationLoadBalancer(loadBalancer, { keepaliveTimeout }); + }).toThrow(`keepaliveTimeout: Must be an int 1 seconds or greater; received ${keepaliveTimeout.toSeconds()}`); +}); + +test.each([ Duration.seconds(181), Duration.minutes(5), -])('VPC origin throws when keepaliveTimeout is %s - out of bounds', (keepaliveTimeout) => { +])('VPC origin allows keepaliveTimeout of %s within the default quota', (keepaliveTimeout) => { // GIVEN const vpc = new ec2.Vpc(stack, 'Vpc'); const loadBalancer = new elbv2.ApplicationLoadBalancer(stack, 'ALB', { vpc }); @@ -231,7 +255,7 @@ test.each([ // WHEN expect(() => { VpcOrigin.withApplicationLoadBalancer(loadBalancer, { keepaliveTimeout }); - }).toThrow(`keepaliveTimeout: Must be an int between 1 and 180 seconds (inclusive); received ${keepaliveTimeout.toSeconds()}`); + }).not.toThrow(); }); test('VPC origin throws when no domainName is specified', () => {