constructor()

in packages/aws-cdk-lib/aws-cloudfront/lib/web-distribution.ts [828:1001]


  constructor(scope: Construct, id: string, props: CloudFrontWebDistributionProps) {
    super(scope, id);
    // Enhanced CDK Analytics Telemetry
    addConstructMetadata(this, props);

    // Comments have an undocumented limit of 128 characters
    const trimmedComment =
      props.comment && props.comment.length > 128
        ? `${props.comment.slice(0, 128 - 3)}...`
        : props.comment;

    const behaviors: BehaviorWithOrigin[] = [];

    const origins: CfnDistribution.OriginProperty[] = [];

    const originGroups: CfnDistribution.OriginGroupProperty[] = [];

    let originIndex = 1;
    for (const originConfig of props.originConfigs) {
      let originId = `origin${originIndex}`;
      const originProperty = this.toOriginProperty(originConfig, originId);

      if (originConfig.failoverCustomOriginSource || originConfig.failoverS3OriginSource) {
        const originSecondaryId = `originSecondary${originIndex}`;
        const originSecondaryProperty = this.toOriginProperty(
          {
            s3OriginSource: originConfig.failoverS3OriginSource,
            customOriginSource: originConfig.failoverCustomOriginSource,
            originPath: originConfig.originPath,
            originHeaders: originConfig.originHeaders,
            originShieldRegion: originConfig.originShieldRegion,
          },
          originSecondaryId,
        );
        const originGroupsId = `OriginGroup${originIndex}`;
        const failoverCodes = originConfig.failoverCriteriaStatusCodes ?? [500, 502, 503, 504];
        originGroups.push({
          id: originGroupsId,
          members: {
            items: [{ originId }, { originId: originSecondaryId }],
            quantity: 2,
          },
          failoverCriteria: {
            statusCodes: {
              items: failoverCodes,
              quantity: failoverCodes.length,
            },
          },
        });
        originId = originGroupsId;
        origins.push(originSecondaryProperty);
      }

      for (const behavior of originConfig.behaviors) {
        behaviors.push({ ...behavior, targetOriginId: originId });
      }

      origins.push(originProperty);
      originIndex++;
    }

    origins.forEach(origin => {
      if (!origin.s3OriginConfig && !origin.customOriginConfig) {
        throw new cdk.ValidationError(`Origin ${origin.domainName} is missing either S3OriginConfig or CustomOriginConfig. At least 1 must be specified.`, this);
      }
    });
    const originGroupsDistConfig =
      originGroups.length > 0
        ? {
          items: originGroups,
          quantity: originGroups.length,
        }
        : undefined;

    const defaultBehaviors = behaviors.filter(behavior => behavior.isDefaultBehavior);
    if (defaultBehaviors.length !== 1) {
      throw new cdk.ValidationError('There can only be one default behavior across all sources. [ One default behavior per distribution ].', this);
    }

    const otherBehaviors: CfnDistribution.CacheBehaviorProperty[] = [];
    for (const behavior of behaviors.filter(b => !b.isDefaultBehavior)) {
      if (!behavior.pathPattern) {
        throw new cdk.ValidationError('pathPattern is required for all non-default behaviors', this);
      }
      otherBehaviors.push(this.toBehavior(behavior, props.viewerProtocolPolicy) as CfnDistribution.CacheBehaviorProperty);
    }

    let distributionConfig: CfnDistribution.DistributionConfigProperty = {
      comment: trimmedComment,
      enabled: props.enabled ?? true,
      defaultRootObject: props.defaultRootObject ?? 'index.html',
      httpVersion: props.httpVersion || HttpVersion.HTTP2,
      priceClass: props.priceClass || PriceClass.PRICE_CLASS_100,
      ipv6Enabled: props.enableIpV6 ?? true,
      // eslint-disable-next-line max-len
      customErrorResponses: props.errorConfigurations, // TODO: validation : https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-customerrorresponse.html#cfn-cloudfront-distribution-customerrorresponse-errorcachingminttl
      webAclId: props.webACLId,

      origins,
      originGroups: originGroupsDistConfig,

      defaultCacheBehavior: this.toBehavior(defaultBehaviors[0], props.viewerProtocolPolicy),
      cacheBehaviors: otherBehaviors.length > 0 ? otherBehaviors : undefined,
    };

    if (props.aliasConfiguration && props.viewerCertificate) {
      throw new cdk.ValidationError([
        'You cannot set both aliasConfiguration and viewerCertificate properties.',
        'Please only use viewerCertificate, as aliasConfiguration is deprecated.',
      ].join(' '), this);
    }

    let _viewerCertificate = props.viewerCertificate;
    if (props.aliasConfiguration) {
      const { acmCertRef, securityPolicy, sslMethod, names: aliases } = props.aliasConfiguration;

      _viewerCertificate = ViewerCertificate.fromAcmCertificate(
        certificatemanager.Certificate.fromCertificateArn(this, 'AliasConfigurationCert', acmCertRef),
        { securityPolicy, sslMethod, aliases },
      );
    }

    if (_viewerCertificate) {
      const { props: viewerCertificate, aliases } = _viewerCertificate;
      Object.assign(distributionConfig, { aliases, viewerCertificate });

      const { minimumProtocolVersion, sslSupportMethod } = viewerCertificate;

      if (minimumProtocolVersion != null && sslSupportMethod != null) {
        const validProtocols = this.VALID_SSL_PROTOCOLS[sslSupportMethod as SSLMethod];

        if (validProtocols.indexOf(minimumProtocolVersion.toString()) === -1) {
          throw new cdk.ValidationError(`${minimumProtocolVersion} is not compabtible with sslMethod ${sslSupportMethod}.\n\tValid Protocols are: ${validProtocols.join(', ')}`, this);
        }
      }
    } else {
      distributionConfig = {
        ...distributionConfig,
        viewerCertificate: { cloudFrontDefaultCertificate: true },
      };
    }

    if (props.loggingConfig) {
      this.loggingBucket = props.loggingConfig.bucket || new s3.Bucket(this, 'LoggingBucket', {
        encryption: s3.BucketEncryption.S3_MANAGED,
      });
      distributionConfig = {
        ...distributionConfig,
        logging: {
          bucket: this.loggingBucket.bucketRegionalDomainName,
          includeCookies: props.loggingConfig.includeCookies || false,
          prefix: props.loggingConfig.prefix,
        },
      };
    }

    if (props.geoRestriction) {
      distributionConfig = {
        ...distributionConfig,
        restrictions: {
          geoRestriction: {
            restrictionType: props.geoRestriction.restrictionType,
            locations: props.geoRestriction.locations,
          },
        },
      };
    }

    const distribution = new CfnDistribution(this, 'CFDistribution', { distributionConfig });
    this.node.defaultChild = distribution;
    this.domainName = distribution.attrDomainName;
    this.distributionDomainName = distribution.attrDomainName;
    this.distributionId = distribution.ref;
  }