@kensio/yulin 1.20.17 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/dist/service/athena/engine/sim-athena-comparison-shims.d.ts +13 -0
  2. package/dist/service/athena/engine/sim-athena-comparison-shims.js +68 -0
  3. package/dist/service/athena/engine/sim-athena-shims.js +2 -0
  4. package/dist/service/cloudformation/resource/cfn/cloudfront/sim-cloudfront-cfn-value-adapter.js +8 -0
  5. package/dist/service/cloudformation/resource/cfn/cloudfront/sim-cloudfront-orp-cfn.d.ts +24 -0
  6. package/dist/service/cloudformation/resource/cfn/cloudfront/sim-cloudfront-orp-cfn.js +31 -0
  7. package/dist/service/cloudfront/behaviour/sim-cloud-front-behavior.d.ts +12 -1
  8. package/dist/service/cloudfront/cache/sim-cf-accept-encoding.d.ts +11 -0
  9. package/dist/service/cloudfront/cache/sim-cf-accept-encoding.js +27 -0
  10. package/dist/service/cloudfront/cache/sim-cf-cache-control.d.ts +28 -0
  11. package/dist/service/cloudfront/cache/sim-cf-cache-control.js +49 -0
  12. package/dist/service/cloudfront/cache/sim-cf-cache-entry-key-path.d.ts +11 -0
  13. package/dist/service/cloudfront/cache/sim-cf-cache-entry-key-path.js +22 -0
  14. package/dist/service/cloudfront/cache/sim-cf-cache-entry-key.d.ts +32 -0
  15. package/dist/service/cloudfront/cache/sim-cf-cache-entry-key.js +112 -0
  16. package/dist/service/cloudfront/cache/sim-cf-cache-status.d.ts +27 -0
  17. package/dist/service/cloudfront/cache/sim-cf-cache-status.js +53 -0
  18. package/dist/service/cloudfront/cache/sim-cf-cache-ttl.d.ts +28 -0
  19. package/dist/service/cloudfront/cache/sim-cf-cache-ttl.js +50 -0
  20. package/dist/service/cloudfront/cache/sim-cf-cacheable-request.d.ts +35 -0
  21. package/dist/service/cloudfront/cache/sim-cf-cacheable-request.js +32 -0
  22. package/dist/service/cloudfront/cache/sim-cf-distribution-cache.d.ts +57 -0
  23. package/dist/service/cloudfront/cache/sim-cf-distribution-cache.js +115 -0
  24. package/dist/service/cloudfront/cache/sim-cf-edge.d.ts +37 -0
  25. package/dist/service/cloudfront/cache/sim-cf-edge.js +34 -0
  26. package/dist/service/cloudfront/cache/sim-cf-error-cache-ttl.d.ts +36 -0
  27. package/dist/service/cloudfront/cache/sim-cf-error-cache-ttl.js +28 -0
  28. package/dist/service/cloudfront/cache/sim-cf-http-date.d.ts +15 -0
  29. package/dist/service/cloudfront/cache/sim-cf-http-date.js +40 -0
  30. package/dist/service/cloudfront/cache-policy/sim-cf-cache-key.d.ts +63 -0
  31. package/dist/service/cloudfront/cache-policy/sim-cf-cache-key.js +70 -0
  32. package/dist/service/cloudfront/cache-policy/sim-cf-cache-policy.d.ts +13 -3
  33. package/dist/service/cloudfront/cache-policy/sim-cf-cache-policy.js +31 -3
  34. package/dist/service/cloudfront/cache-policy/sim-cf-managed-cache-policies.d.ts +8 -3
  35. package/dist/service/cloudfront/cache-policy/sim-cf-managed-cache-policies.js +96 -12
  36. package/dist/service/cloudfront/cff/sim-cff-search-distribution.fixture.js +4 -0
  37. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-config.d.ts +9 -8
  38. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-config.js +40 -11
  39. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-key.d.ts +10 -0
  40. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-key.js +50 -0
  41. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-section.d.ts +28 -0
  42. package/dist/service/cloudfront/cfn/cache-policy/sim-cfn-cf-cache-policy-section.js +29 -0
  43. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-behavior-policy-kinds.d.ts +16 -0
  44. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-behavior-policy-kinds.js +23 -0
  45. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-behavior-policies.d.ts +3 -2
  46. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-behavior-policies.js +3 -2
  47. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-creator.d.ts +6 -6
  48. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-creator.js +6 -6
  49. package/dist/service/cloudfront/cfn/distro/sim-cfn-cf-distro-policy-drops.js +8 -23
  50. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-config.d.ts +28 -0
  51. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-config.js +46 -0
  52. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-creator.d.ts +24 -0
  53. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-creator.js +32 -0
  54. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-forwarding.d.ts +10 -0
  55. package/dist/service/cloudfront/cfn/origin-request-policy/sim-cfn-cf-orp-forwarding.js +51 -0
  56. package/dist/service/cloudfront/cfn/policy/sim-cfn-cf-policy-section.d.ts +22 -0
  57. package/dist/service/cloudfront/cfn/policy/sim-cfn-cf-policy-section.js +54 -0
  58. package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.d.ts +1 -0
  59. package/dist/service/cloudfront/cfn/sim-cfn-cloudfront-resource-factory.js +12 -0
  60. package/dist/service/cloudfront/command/create-distribution/create-distribution.command.d.ts +1 -0
  61. package/dist/service/cloudfront/command/create-distribution/create-distribution.handler.d.ts +2 -0
  62. package/dist/service/cloudfront/command/invalidation/sim-cf-create-invalidation.d.ts +28 -0
  63. package/dist/service/cloudfront/command/invalidation/sim-cf-create-invalidation.js +59 -0
  64. package/dist/service/cloudfront/command/invalidation/sim-cf-get-invalidation.d.ts +19 -0
  65. package/dist/service/cloudfront/command/invalidation/sim-cf-get-invalidation.js +32 -0
  66. package/dist/service/cloudfront/command/invalidation/sim-cf-invalidation-access.d.ts +36 -0
  67. package/dist/service/cloudfront/command/invalidation/sim-cf-invalidation-access.js +45 -0
  68. package/dist/service/cloudfront/command/invalidation/sim-cf-invalidation-command.types.d.ts +80 -0
  69. package/dist/service/cloudfront/command/invalidation/sim-cf-invalidation-command.types.js +1 -0
  70. package/dist/service/cloudfront/command/invalidation/sim-cf-invalidation-commands.d.ts +39 -0
  71. package/dist/service/cloudfront/command/invalidation/sim-cf-invalidation-commands.js +35 -0
  72. package/dist/service/cloudfront/command/invalidation/sim-cf-list-invalidations.d.ts +23 -0
  73. package/dist/service/cloudfront/command/invalidation/sim-cf-list-invalidations.js +39 -0
  74. package/dist/service/cloudfront/command/update-distribution/update-distribution.handler.d.ts +2 -0
  75. package/dist/service/cloudfront/controller/content/sim-cf-content-stage.d.ts +51 -0
  76. package/dist/service/cloudfront/controller/content/sim-cf-content-stage.js +65 -0
  77. package/dist/service/cloudfront/controller/dependency/sim-cf-controller-dependency.d.ts +2 -3
  78. package/dist/service/cloudfront/controller/dependency/sim-cf-controller-dependency.js +4 -4
  79. package/dist/service/cloudfront/controller/error/sim-cf-custom-error-responder.d.ts +4 -0
  80. package/dist/service/cloudfront/controller/error/sim-cf-custom-error-responder.js +12 -8
  81. package/dist/service/cloudfront/controller/origin/sim-cf-origin-stage.d.ts +2 -2
  82. package/dist/service/cloudfront/controller/origin/sim-cf-origin-stage.js +2 -2
  83. package/dist/service/cloudfront/controller/sim-cloudfront-request-pipeline.d.ts +6 -6
  84. package/dist/service/cloudfront/controller/sim-cloudfront-request-pipeline.js +35 -20
  85. package/dist/service/cloudfront/custom-error/sim-cloudfront-custom-error-response.d.ts +23 -5
  86. package/dist/service/cloudfront/custom-error/sim-cloudfront-custom-error-response.js +8 -0
  87. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-origin-request-policy.d.ts +18 -0
  88. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-origin-request-policy.js +30 -0
  89. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-policies.d.ts +7 -5
  90. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-policies.js +8 -5
  91. package/dist/service/cloudfront/distribution/configurator/sim-cf-behavior-properties.js +4 -1
  92. package/dist/service/cloudfront/distribution/configurator/sim-cf-distribution-configurator.factory.d.ts +2 -0
  93. package/dist/service/cloudfront/distribution/configurator/sim-cf-distribution-configurator.factory.js +6 -2
  94. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-custom-error-configurator.d.ts +13 -3
  95. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-custom-error-configurator.js +27 -6
  96. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-origin-configurator.d.ts +3 -1
  97. package/dist/service/cloudfront/distribution/configurator/sim-cloud-front-origin-configurator.js +4 -1
  98. package/dist/service/cloudfront/distribution/sim-cf-distribution-configuration-state.d.ts +5 -3
  99. package/dist/service/cloudfront/distribution/sim-cf-distribution-reconfigurer.d.ts +2 -0
  100. package/dist/service/cloudfront/distribution/sim-cf-distribution-view.js +1 -1
  101. package/dist/service/cloudfront/distribution/sim-cloudfront-distribution.d.ts +25 -2
  102. package/dist/service/cloudfront/distribution/sim-cloudfront-distribution.js +24 -0
  103. package/dist/service/cloudfront/error/sim-cf-invalidation.error.d.ts +22 -0
  104. package/dist/service/cloudfront/error/sim-cf-invalidation.error.js +26 -0
  105. package/dist/service/cloudfront/error/sim-cf-origin-request-policy.error.d.ts +22 -0
  106. package/dist/service/cloudfront/error/sim-cf-origin-request-policy.error.js +26 -0
  107. package/dist/service/cloudfront/index.d.ts +2 -0
  108. package/dist/service/cloudfront/index.js +1 -0
  109. package/dist/service/cloudfront/invalidation/sim-cf-invalidation-path.d.ts +22 -0
  110. package/dist/service/cloudfront/invalidation/sim-cf-invalidation-path.js +32 -0
  111. package/dist/service/cloudfront/invalidation/sim-cf-invalidation-view.d.ts +43 -0
  112. package/dist/service/cloudfront/invalidation/sim-cf-invalidation-view.js +33 -0
  113. package/dist/service/cloudfront/invalidation/sim-cf-invalidation.d.ts +55 -0
  114. package/dist/service/cloudfront/invalidation/sim-cf-invalidation.js +56 -0
  115. package/dist/service/cloudfront/invalidation/sim-cf-invalidations.d.ts +41 -0
  116. package/dist/service/cloudfront/invalidation/sim-cf-invalidations.js +58 -0
  117. package/dist/service/cloudfront/invalidation/sim-cf-repeated-invalidation.d.ts +15 -0
  118. package/dist/service/cloudfront/invalidation/sim-cf-repeated-invalidation.js +23 -0
  119. package/dist/service/cloudfront/origin/custom/sim-cf-custom-origin-forwarding.d.ts +19 -0
  120. package/dist/service/cloudfront/origin/custom/sim-cf-custom-origin-forwarding.js +116 -0
  121. package/dist/service/cloudfront/origin/custom/sim-cf-custom-origin-request.d.ts +15 -5
  122. package/dist/service/cloudfront/origin/custom/sim-cf-custom-origin-request.js +13 -8
  123. package/dist/service/cloudfront/origin/custom/sim-cf-custom-origin-signer.js +8 -5
  124. package/dist/service/cloudfront/origin/custom/sim-cloudfront-custom-origin.d.ts +13 -0
  125. package/dist/service/cloudfront/origin/custom/sim-cloudfront-custom-origin.js +8 -0
  126. package/dist/service/cloudfront/origin-request-policy/sim-cf-behavior-forwarded.d.ts +24 -0
  127. package/dist/service/cloudfront/origin-request-policy/sim-cf-behavior-forwarded.js +21 -0
  128. package/dist/service/cloudfront/origin-request-policy/sim-cf-forwarded-to-origin.d.ts +57 -0
  129. package/dist/service/cloudfront/origin-request-policy/sim-cf-forwarded-to-origin.js +129 -0
  130. package/dist/service/cloudfront/origin-request-policy/sim-cf-managed-origin-request-policies.d.ts +30 -0
  131. package/dist/service/cloudfront/origin-request-policy/sim-cf-managed-origin-request-policies.js +121 -0
  132. package/dist/service/cloudfront/origin-request-policy/sim-cf-origin-request-forwarding.d.ts +56 -0
  133. package/dist/service/cloudfront/origin-request-policy/sim-cf-origin-request-forwarding.js +67 -0
  134. package/dist/service/cloudfront/origin-request-policy/sim-cf-origin-request-policy-registry.d.ts +38 -0
  135. package/dist/service/cloudfront/origin-request-policy/sim-cf-origin-request-policy-registry.js +51 -0
  136. package/dist/service/cloudfront/origin-request-policy/sim-cf-origin-request-policy.d.ts +32 -0
  137. package/dist/service/cloudfront/origin-request-policy/sim-cf-origin-request-policy.js +30 -0
  138. package/dist/service/cloudfront/registry/sim-cloud-front-registry.d.ts +25 -0
  139. package/dist/service/cloudfront/registry/sim-cloud-front-registry.js +23 -0
  140. package/dist/service/cloudfront/sdk/sim-cloudfront-sdk-command-router.js +12 -0
  141. package/dist/service/cloudfront/sim-cloudfront-caching.d.ts +31 -0
  142. package/dist/service/cloudfront/sim-cloudfront-caching.js +38 -0
  143. package/dist/service/cloudfront/sim-cloudfront-commands.d.ts +12 -0
  144. package/dist/service/cloudfront/sim-cloudfront-commands.js +12 -0
  145. package/dist/service/cloudfront/sim-cloudfront-distributions.d.ts +21 -0
  146. package/dist/service/cloudfront/sim-cloudfront-distributions.js +23 -0
  147. package/dist/service/cloudfront/sim-cloudfront-origin-access-controls.d.ts +30 -0
  148. package/dist/service/cloudfront/sim-cloudfront-origin-access-controls.js +35 -0
  149. package/dist/service/cloudfront/sim-cloudfront-policies.d.ts +22 -5
  150. package/dist/service/cloudfront/sim-cloudfront-policies.js +27 -5
  151. package/dist/service/cloudfront/sim-cloudfront.d.ts +15 -31
  152. package/dist/service/cloudfront/sim-cloudfront.js +23 -41
  153. package/dist/service/iam/authorize/allow/sim-iam-allow-requirement.d.ts +6 -5
  154. package/dist/service/iam/authorize/allow/sim-iam-allow-requirement.js +6 -5
  155. package/dist/service/iam/authorize/context/sim-iam-auth-z-input.d.ts +6 -4
  156. package/dist/service/kms/command/sim-kms-request-options.d.ts +9 -5
  157. package/dist/service/logs/command/delivery/sim-logs-delivery-source-commands.d.ts +6 -4
  158. package/dist/service/logs/command/delivery/sim-logs-delivery-source-commands.js +13 -4
  159. package/dist/service/logs/delivery/cloudfront/sim-logs-vended-log-delivery.d.ts +23 -0
  160. package/dist/service/logs/delivery/cloudfront/sim-logs-vended-log-delivery.js +28 -0
  161. package/dist/service/ssm/parameter/sim-ssm-kms-crypto.d.ts +7 -10
  162. package/dist/service/ssm/parameter/sim-ssm-parameter-kms.d.ts +10 -11
  163. package/dist/service/ssm/parameter/sim-ssm-parameter-kms.js +11 -16
  164. package/docs/services/athena/README.md +7 -1
  165. package/docs/services/cloudformation/README.md +2 -1
  166. package/docs/services/cloudfront/README.md +903 -25
  167. package/docs/services/ecs/README.md +5 -2
  168. package/docs/services/kms/README.md +9 -5
  169. package/docs/services/logs/README.md +6 -0
  170. package/docs/services/ssm/README.md +26 -33
  171. package/package.json +1 -1
@@ -262,8 +262,12 @@ fetching it, as in CloudFront.
262
262
  A viewer-response function never sees a custom error page. CloudFront runs no viewer-response
263
263
  function once the Origin has answered 400 or higher, and simulated CloudFront does the same, for a
264
264
  CloudFront Function and a Lambda@Edge function alike. The status the Origin returned is what decides
265
- that, whatever `ResponseCode` puts in its place. `ErrorCachingMinTTL` is accepted and ignored, along
266
- with a rule that sets nothing else, since sim CloudFront has no cache to apply it to.
265
+ that, whatever `ResponseCode` puts in its place.
266
+
267
+ `ErrorCachingMinTTL` says how many seconds the Distribution holds the error for before it reads the
268
+ Origin again. A rule carrying it alone, with no `ResponsePagePath`, configures error caching for a
269
+ status the Distribution serves no page for. See
270
+ [What a Distribution stores](#what-a-distribution-stores).
267
271
 
268
272
  ## Serve simulated CloudFront on localhost
269
273
 
@@ -1553,6 +1557,10 @@ error status. It runs on whatever the Origin answered, including a 400 and above
1553
1557
  origin events differ from the viewer events, and CloudFront documents it. Returning a response
1554
1558
  replaces what the viewer gets.
1555
1559
 
1560
+ Both origin events run on a cache miss alone. A hit answers the viewer without either of them, as
1561
+ does a request a web ACL blocked or a viewer-request function answered. An `origin-request` function
1562
+ returning a response leaves the Origin unread, with no `origin-response` event after it.
1563
+
1556
1564
  At both origin events the `host` header holds the Origin's own domain name. A viewer event shows the
1557
1565
  domain the viewer used.
1558
1566
 
@@ -2221,13 +2229,16 @@ const stack = await simAws.cloudFormation().deployTemplate({
2221
2229
  CachePolicyConfig: {
2222
2230
  Name: "BeaconPolicy",
2223
2231
  MinTTL: 0,
2224
- DefaultTTL: 0,
2225
- MaxTTL: 0,
2232
+ DefaultTTL: 60,
2233
+ MaxTTL: 3600,
2226
2234
  ParametersInCacheKeyAndForwardedToOrigin: {
2227
- EnableAcceptEncodingGzip: false,
2235
+ EnableAcceptEncodingGzip: true,
2228
2236
  CookiesConfig: { CookieBehavior: "none" },
2229
2237
  HeadersConfig: { HeaderBehavior: "none" },
2230
- QueryStringsConfig: { QueryStringBehavior: "none" },
2238
+ QueryStringsConfig: {
2239
+ QueryStringBehavior: "whitelist",
2240
+ QueryStrings: ["page"],
2241
+ },
2231
2242
  },
2232
2243
  },
2233
2244
  },
@@ -2287,18 +2298,37 @@ console.log(
2287
2298
  config?.CacheBehaviors?.Items?.[0]?.CachePolicyId ===
2288
2299
  stack.output("BeaconPolicyId"),
2289
2300
  );
2301
+
2302
+ // The policy itself, holding the TTLs and the cache key the template gave it.
2303
+ const beaconPolicy = simAws
2304
+ .cloudFront()
2305
+ .getCachePolicyById(stack.output("BeaconPolicyId"));
2306
+
2307
+ console.log(beaconPolicy?.defaultTtlSec); // 60
2308
+ console.log(beaconPolicy?.cacheKey.queryStringBehavior); // "whitelist"
2309
+ console.log(beaconPolicy?.cacheKey.queryStrings); // ["page"]
2290
2310
  ```
2291
2311
 
2292
2312
  A Behavior records the ID it was given, and `GetDistribution` reports it back for both the default
2293
2313
  Behavior and a named one. An update changing the policy is reported the same way.
2294
2314
 
2295
- Nothing here reads the policy itself. The TTLs, the cache key and the compression settings need a
2296
- cache, and sim CloudFront holds none. Every request reaches the Origin whatever the policy would
2297
- have cached on real CloudFront.
2315
+ The policy itself carries everything `CachePolicyConfig` holds. `getCachePolicyById` hands back the
2316
+ three TTLs, the three sections of `ParametersInCacheKeyAndForwardedToOrigin` and the two
2317
+ `EnableAcceptEncoding` flags. A test can assert that its Behavior leaves the query string out of the
2318
+ cache key before sim CloudFront has a cache to key.
2319
+
2320
+ The Distribution reads the policy on every request. The cache key comes from the three sections and
2321
+ the two flags, and a `MaxTTL` of zero is what makes a Behavior on `CachingDisabled` reach the Origin
2322
+ every time. [Caching](#caching) below covers what is stored and what is keyed on.
2323
+
2324
+ A TTL the template left out falls back to CloudFront's own default (0 seconds for `MinTTL`, one day
2325
+ for `DefaultTTL` and 365 days for `MaxTTL`), and a `MinTTL` above a day raises the `DefaultTTL` with
2326
+ it the way CloudFront does. An absent cache key section falls back to `none`. A section naming a
2327
+ behaviour CloudFront does not offer fails the Stack, naming the Resource. `HeaderBehavior` takes
2328
+ `none` and `whitelist` alone, where CloudFront gives an origin request policy a wider set.
2298
2329
 
2299
2330
  A policy name is unique within an account, as it is in CloudFront. A second
2300
2331
  `AWS::CloudFront::CachePolicy` claiming a name is refused with `CachePolicyAlreadyExists`.
2301
- `Name` and `Comment` are the parts of `CachePolicyConfig` the policy carries.
2302
2332
 
2303
2333
  ### Managed cache policies
2304
2334
 
@@ -2314,6 +2344,10 @@ Behavior names one without a template creating anything. `CachingOptimized`
2314
2344
  for it. CDK's `CachePolicy.CACHING_OPTIMIZED` and its six siblings synthesize those IDs. A stack
2315
2345
  reaching for one deploys.
2316
2346
 
2347
+ Each also carries the TTLs and the cache key AWS publishes for it. A Behavior on `CachingOptimized`
2348
+ here holds the same 1 second floor, the same day of default TTL and the same empty cache key as one
2349
+ in an account.
2350
+
2317
2351
  The managed policies sit in CloudFront's own namespace. A template may create a policy called
2318
2352
  `CachingDisabled` of its own, and deleting that stack leaves the managed one where it was.
2319
2353
 
@@ -2324,6 +2358,830 @@ way an absent response headers policy does, and the Behavior reports no policy.
2324
2358
  `CreateDistribution` and `UpdateDistribution` still refuse the same ID with `NoSuchCachePolicy`, as
2325
2359
  real CloudFront refuses it.
2326
2360
 
2361
+ ## Caching
2362
+
2363
+ A Distribution holds a cache. A request for a key it already holds is answered from that cache,
2364
+ leaving the Origin unread. The Behavior's cache policy decides the key, and decides whether the
2365
+ Behavior has one at all. The policy and the Origin's own cache headers together decide how long an
2366
+ answer is held.
2367
+
2368
+ ```typescript sim-cloudfront-caching
2369
+ /**
2370
+ * Serving a request from a Distribution's cache, and missing it at another
2371
+ * edge.
2372
+ */
2373
+
2374
+ import { CreateDistributionCommand } from "@aws-sdk/client-cloudfront";
2375
+ import {
2376
+ CreateBucketCommand,
2377
+ PutBucketPolicyCommand,
2378
+ PutObjectCommand,
2379
+ PutPublicAccessBlockCommand,
2380
+ } from "@aws-sdk/client-s3";
2381
+
2382
+ import { SimAws } from "@kensio/yulin";
2383
+ import { serveSimAws } from "@kensio/yulin/serve";
2384
+
2385
+ const simAws = new SimAws();
2386
+ const srv = await serveSimAws({ simAws });
2387
+
2388
+ try {
2389
+ const simS3 = simAws.s3();
2390
+
2391
+ await simS3.createBucket(new CreateBucketCommand({ Bucket: "site-bucket" }));
2392
+ await simS3.putPublicAccessBlock(
2393
+ new PutPublicAccessBlockCommand({
2394
+ Bucket: "site-bucket",
2395
+ PublicAccessBlockConfiguration: {
2396
+ BlockPublicAcls: true,
2397
+ IgnorePublicAcls: true,
2398
+ },
2399
+ }),
2400
+ );
2401
+ await simS3.putBucketPolicy(
2402
+ new PutBucketPolicyCommand({
2403
+ Bucket: "site-bucket",
2404
+ Policy: JSON.stringify({
2405
+ Version: "2012-10-17",
2406
+ Statement: {
2407
+ Effect: "Allow",
2408
+ Principal: "*",
2409
+ Action: "s3:GetObject",
2410
+ Resource: "arn:aws:s3:::site-bucket/*",
2411
+ },
2412
+ }),
2413
+ }),
2414
+ );
2415
+
2416
+ const publish = async (body: string): Promise<void> => {
2417
+ await simS3.putObject(
2418
+ new PutObjectCommand({
2419
+ Bucket: "site-bucket",
2420
+ Key: "index.html",
2421
+ ContentType: "text/html",
2422
+ Body: body,
2423
+ }),
2424
+ );
2425
+ };
2426
+
2427
+ await publish("<h1>First</h1>");
2428
+
2429
+ const distributionCreation = await simAws.cloudFront().createDistribution(
2430
+ new CreateDistributionCommand({
2431
+ DistributionConfig: {
2432
+ CallerReference: "cached-site",
2433
+ Comment: "Cached site",
2434
+ Enabled: true,
2435
+ DefaultRootObject: "index.html",
2436
+ Origins: {
2437
+ Quantity: 1,
2438
+ Items: [
2439
+ {
2440
+ Id: "site-origin",
2441
+ DomainName: "site-bucket.s3.amazonaws.com",
2442
+ S3OriginConfig: { OriginAccessIdentity: "" },
2443
+ },
2444
+ ],
2445
+ },
2446
+ DefaultCacheBehavior: {
2447
+ TargetOriginId: "site-origin",
2448
+ ViewerProtocolPolicy: "allow-all",
2449
+ // CachingOptimized, one of CloudFront's managed policies.
2450
+ CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
2451
+ },
2452
+ },
2453
+ }),
2454
+ );
2455
+
2456
+ const distroHostname = distributionCreation.Distribution!.DomainName!;
2457
+ const home = srv.localUrl(`http://${distroHostname}/`);
2458
+
2459
+ const first = await fetch(home);
2460
+ console.log(first.headers.get("x-cache")); // Miss from cloudfront
2461
+ console.log(await first.text()); // <h1>First</h1>
2462
+
2463
+ // The Bucket holds a new page, which the Distribution has not been told
2464
+ // about.
2465
+ await publish("<h1>Second</h1>");
2466
+
2467
+ const second = await fetch(home);
2468
+ console.log(second.headers.get("x-cache")); // Hit from cloudfront
2469
+ console.log(await second.text()); // <h1>First</h1>
2470
+
2471
+ // The entry goes on ageing while simulated time moves.
2472
+ await simAws.clock().advanceBy({ seconds: 30 });
2473
+
2474
+ const aged = await fetch(home);
2475
+ console.log(aged.headers.get("age")); // 30
2476
+
2477
+ // Another point of presence has nothing cached under that key.
2478
+ const coldEdge = await fetch(home, {
2479
+ headers: { "x-sim-aws-cloudfront-edge": "second-edge" },
2480
+ });
2481
+ console.log(await coldEdge.text()); // <h1>Second</h1>
2482
+
2483
+ // With caching off, every request reaches the Origin.
2484
+ simAws.cloudFront().configureCaching({ enabled: false });
2485
+
2486
+ const uncached = await fetch(home);
2487
+ console.log(await uncached.text()); // <h1>Second</h1>
2488
+ } finally {
2489
+ await srv.close();
2490
+ }
2491
+ ```
2492
+
2493
+ ### What the key is made of
2494
+
2495
+ The key is the request path, plus whatever the Behavior's cache policy names. A query string, a
2496
+ header or a cookie the policy lists joins the key. Two requests differing only in a campaign
2497
+ parameter the policy leaves out share one entry. Where the policy enables gzip or brotli, the
2498
+ normalized `Accept-Encoding` joins the key, and one object is cached once compressed and once
2499
+ plain.
2500
+
2501
+ The request method is part of the key as well, since a HEAD response carries no body and a GET
2502
+ response does. `CachedMethods` on the Behavior decides which methods are cached at all. It is `GET`
2503
+ and `HEAD` unless the Behavior widens it, and a POST reaches the Origin every time.
2504
+
2505
+ ### The edge a request arrives at
2506
+
2507
+ CloudFront caches at each of its points of presence, several hundred of them, and one viewer's
2508
+ request fills the cache at one of them. The key carries an edge ID for that. Every request arrives
2509
+ at the same edge unless it sends an `x-sim-aws-cloudfront-edge` header naming another. A test that
2510
+ sends a different one is proving its app survives arriving somewhere cold.
2511
+
2512
+ The header follows the `x-sim-aws-*` convention of the caller and request source headers, and
2513
+ `@kensio/yulin/cloudfront` exports the name as `simCfEdgeHeaderName`. Sim CloudFront takes it off
2514
+ the request once it has read it. A web ACL rule, a CloudFront Function, a
2515
+ Lambda@Edge function and the Origin all see the request the viewer sent without it.
2516
+
2517
+ ### What a Distribution stores
2518
+
2519
+ A Behavior stores what it serves where its cache policy is one this simulation holds and that
2520
+ policy's `MaxTTL` is above zero. That leaves out a Behavior naming a `CachePolicyId` from a real
2521
+ account, a Behavior naming none at all, and a Behavior on `CachingDisabled`. The alternative in each
2522
+ case would be a guessed TTL.
2523
+
2524
+ An error is held for a TTL of its own. It comes from the `ErrorCachingMinTTL` of the custom error
2525
+ response matching the status, and from CloudFront's ten seconds where the Distribution configures no
2526
+ rule for that status. The Origin's cache headers and the Behavior's cache policy have no say in it.
2527
+ A rule with `ErrorCachingMinTTL: 0` holds the error for no time at all, and every failing request
2528
+ reaches the Origin. A rule is matched on the status the Origin answered with. A 404 the Distribution
2529
+ serves as a 200 error page is held for the seconds the 404's own rule allows.
2530
+
2531
+ ### How long an entry is held
2532
+
2533
+ An entry records the instant it expires, taken from the simulation's clock. A request arriving after
2534
+ that instant reaches the Origin, and what the Origin answers takes the expired entry's place. So a
2535
+ test reaches the moment its content goes stale by advancing simulated time, without waiting for it.
2536
+
2537
+ ```typescript sim-cloudfront-cache-expiry
2538
+ /**
2539
+ * Expiring a cached object by moving simulated time past its cache control.
2540
+ */
2541
+
2542
+ import { CreateDistributionCommand } from "@aws-sdk/client-cloudfront";
2543
+ import {
2544
+ CreateBucketCommand,
2545
+ PutBucketPolicyCommand,
2546
+ PutObjectCommand,
2547
+ PutPublicAccessBlockCommand,
2548
+ } from "@aws-sdk/client-s3";
2549
+
2550
+ import { SimAws } from "@kensio/yulin";
2551
+ import { serveSimAws } from "@kensio/yulin/serve";
2552
+
2553
+ const simAws = new SimAws();
2554
+ const srv = await serveSimAws({ simAws });
2555
+
2556
+ try {
2557
+ const simS3 = simAws.s3();
2558
+
2559
+ await simS3.createBucket(new CreateBucketCommand({ Bucket: "news-bucket" }));
2560
+ await simS3.putPublicAccessBlock(
2561
+ new PutPublicAccessBlockCommand({
2562
+ Bucket: "news-bucket",
2563
+ PublicAccessBlockConfiguration: {
2564
+ BlockPublicAcls: true,
2565
+ IgnorePublicAcls: true,
2566
+ },
2567
+ }),
2568
+ );
2569
+ await simS3.putBucketPolicy(
2570
+ new PutBucketPolicyCommand({
2571
+ Bucket: "news-bucket",
2572
+ Policy: JSON.stringify({
2573
+ Version: "2012-10-17",
2574
+ Statement: {
2575
+ Effect: "Allow",
2576
+ Principal: "*",
2577
+ Action: "s3:GetObject",
2578
+ Resource: "arn:aws:s3:::news-bucket/*",
2579
+ },
2580
+ }),
2581
+ }),
2582
+ );
2583
+
2584
+ // The Origin holds each version of the page for a minute.
2585
+ const publish = async (body: string): Promise<void> => {
2586
+ await simS3.putObject(
2587
+ new PutObjectCommand({
2588
+ Bucket: "news-bucket",
2589
+ Key: "index.html",
2590
+ ContentType: "text/html",
2591
+ CacheControl: "max-age=60",
2592
+ Body: body,
2593
+ }),
2594
+ );
2595
+ };
2596
+
2597
+ await publish("<h1>First</h1>");
2598
+
2599
+ const distributionCreation = await simAws.cloudFront().createDistribution(
2600
+ new CreateDistributionCommand({
2601
+ DistributionConfig: {
2602
+ CallerReference: "news-site",
2603
+ Comment: "News site",
2604
+ Enabled: true,
2605
+ DefaultRootObject: "index.html",
2606
+ Origins: {
2607
+ Quantity: 1,
2608
+ Items: [
2609
+ {
2610
+ Id: "news-origin",
2611
+ DomainName: "news-bucket.s3.amazonaws.com",
2612
+ S3OriginConfig: { OriginAccessIdentity: "" },
2613
+ },
2614
+ ],
2615
+ },
2616
+ DefaultCacheBehavior: {
2617
+ TargetOriginId: "news-origin",
2618
+ ViewerProtocolPolicy: "allow-all",
2619
+ // CachingOptimized, one of CloudFront's managed policies.
2620
+ CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
2621
+ },
2622
+ },
2623
+ }),
2624
+ );
2625
+
2626
+ const distroHostname = distributionCreation.Distribution!.DomainName!;
2627
+ const home = srv.localUrl(`http://${distroHostname}/`);
2628
+
2629
+ const first = await fetch(home);
2630
+ console.log(await first.text()); // <h1>First</h1>
2631
+
2632
+ await publish("<h1>Second</h1>");
2633
+
2634
+ // Still inside the minute the Origin asked for.
2635
+ const held = await fetch(home);
2636
+ console.log(await held.text()); // <h1>First</h1>
2637
+
2638
+ // Simulated time moves past it, and the next request reaches the Origin.
2639
+ await simAws.clock().advanceBy({ seconds: 61 });
2640
+
2641
+ const expired = await fetch(home);
2642
+ console.log(await expired.text()); // <h1>Second</h1>
2643
+ } finally {
2644
+ await srv.close();
2645
+ }
2646
+ ```
2647
+
2648
+ The Origin's own headers and the cache policy settle the TTL between them, the way they settle it in
2649
+ AWS. `s-maxage` is preferred to `max-age`, and `max-age` to `Expires`. Whatever the Origin asks for
2650
+ is held between the policy's `MinTTL` and `MaxTTL`. An Origin that asks for nothing gets the greater
2651
+ of `MinTTL` and `DefaultTTL`, which is a day on `CachingOptimized`.
2652
+
2653
+ An `Expires` header has to carry one of the three date formats HTTP allows. Anything else, a
2654
+ locale-formatted date included, is read as an object that expired already, the way any HTTP cache
2655
+ reads it.
2656
+
2657
+ `no-store`, `no-cache` and `private` keep the answer out of the cache while the policy's `MinTTL` is
2658
+ zero. Where it is higher, the floor overrides the Origin and the answer is held for `MinTTL`
2659
+ seconds. That last one is CloudFront's own behaviour, and the
2660
+ [AWS documentation](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html)
2661
+ carries a warning about it.
2662
+
2663
+ ### Telling a hit from a miss
2664
+
2665
+ An answer the cache or the Origin produced carries `X-Cache`. It reads `Hit from cloudfront` where
2666
+ the Distribution held the object and `Miss from cloudfront` where the Origin answered. A response
2667
+ returned earlier in the pipeline (one a web ACL blocked, or one a viewer-request function answered
2668
+ with) carries none. A hit carries `Age` as well, the whole seconds the entry has been held, counted
2669
+ on the simulation's clock from the moment the Origin answered. Advancing simulated time by a minute
2670
+ adds 60 to the age the next hit reports.
2671
+
2672
+ Both headers go on ahead of the Behavior's response headers policy and the viewer-response event. A
2673
+ policy listing `X-Cache` among its headers to remove takes it off, and a viewer-response CloudFront
2674
+ Function or Lambda@Edge function reads both in its event.
2675
+
2676
+ A hit is answered without running either origin event. `origin-request` and `origin-response` run on
2677
+ the miss that filled the cache and on nothing after it, as they do on AWS. The viewer events run
2678
+ either way, and so does the Behavior's response headers policy.
2679
+
2680
+ ### Applying a response headers policy
2681
+
2682
+ A response headers policy is applied to a response on its way out of the cache, as CloudFront
2683
+ applies one. The stored entry carries the Origin's own headers. A Behavior given a different policy
2684
+ therefore serves what it already holds under the new one, with no invalidation.
2685
+
2686
+ ### Turning it off
2687
+
2688
+ `simAws.cloudFront().configureCaching({ enabled: false })` turns caching off for every Distribution
2689
+ in one `SimAws`, across every Account and Region. Caching is on by default, as CloudFront's is. A
2690
+ suite that repeats a request and wants each one to reach the Origin can turn it off in setup.
2691
+
2692
+ ## Invalidations
2693
+
2694
+ `CreateInvalidation` clears what a Distribution has cached. The next request for a cleared path
2695
+ reaches the Origin. This is the step a deploy takes once it has published new files, and it decides
2696
+ whether anyone sees them.
2697
+
2698
+ ```typescript sim-cloudfront-invalidation
2699
+ /**
2700
+ * Clearing what a Distribution has cached, and reading the invalidation back.
2701
+ */
2702
+
2703
+ import {
2704
+ CreateDistributionCommand,
2705
+ CreateInvalidationCommand,
2706
+ GetInvalidationCommand,
2707
+ ListInvalidationsCommand,
2708
+ } from "@aws-sdk/client-cloudfront";
2709
+ import {
2710
+ CreateBucketCommand,
2711
+ PutBucketPolicyCommand,
2712
+ PutObjectCommand,
2713
+ PutPublicAccessBlockCommand,
2714
+ } from "@aws-sdk/client-s3";
2715
+
2716
+ import { SimAws } from "@kensio/yulin";
2717
+ import { serveSimAws } from "@kensio/yulin/serve";
2718
+
2719
+ const simAws = new SimAws();
2720
+ const srv = await serveSimAws({ simAws });
2721
+
2722
+ try {
2723
+ const simS3 = simAws.s3();
2724
+
2725
+ await simS3.createBucket(
2726
+ new CreateBucketCommand({ Bucket: "release-bucket" }),
2727
+ );
2728
+ await simS3.putPublicAccessBlock(
2729
+ new PutPublicAccessBlockCommand({
2730
+ Bucket: "release-bucket",
2731
+ PublicAccessBlockConfiguration: {
2732
+ BlockPublicAcls: true,
2733
+ IgnorePublicAcls: true,
2734
+ },
2735
+ }),
2736
+ );
2737
+ await simS3.putBucketPolicy(
2738
+ new PutBucketPolicyCommand({
2739
+ Bucket: "release-bucket",
2740
+ Policy: JSON.stringify({
2741
+ Version: "2012-10-17",
2742
+ Statement: {
2743
+ Effect: "Allow",
2744
+ Principal: "*",
2745
+ Action: "s3:GetObject",
2746
+ Resource: "arn:aws:s3:::release-bucket/*",
2747
+ },
2748
+ }),
2749
+ }),
2750
+ );
2751
+
2752
+ const publish = async (body: string): Promise<void> => {
2753
+ await simS3.putObject(
2754
+ new PutObjectCommand({
2755
+ Bucket: "release-bucket",
2756
+ Key: "index.html",
2757
+ ContentType: "text/html",
2758
+ Body: body,
2759
+ }),
2760
+ );
2761
+ };
2762
+
2763
+ await publish("<h1>First</h1>");
2764
+
2765
+ const simCloudFront = simAws.cloudFront();
2766
+ const distributionCreation = await simCloudFront.createDistribution(
2767
+ new CreateDistributionCommand({
2768
+ DistributionConfig: {
2769
+ CallerReference: "released-site",
2770
+ Comment: "Released site",
2771
+ Enabled: true,
2772
+ DefaultRootObject: "index.html",
2773
+ Origins: {
2774
+ Quantity: 1,
2775
+ Items: [
2776
+ {
2777
+ Id: "site-origin",
2778
+ DomainName: "release-bucket.s3.amazonaws.com",
2779
+ S3OriginConfig: { OriginAccessIdentity: "" },
2780
+ },
2781
+ ],
2782
+ },
2783
+ DefaultCacheBehavior: {
2784
+ TargetOriginId: "site-origin",
2785
+ ViewerProtocolPolicy: "allow-all",
2786
+ // CachingOptimized, one of CloudFront's managed policies.
2787
+ CachePolicyId: "658327ea-f89d-4fab-a63d-7e88639e58f6",
2788
+ },
2789
+ },
2790
+ }),
2791
+ );
2792
+
2793
+ const distributionId = distributionCreation.Distribution!.Id!;
2794
+ const distroHostname = distributionCreation.Distribution!.DomainName!;
2795
+ const home = srv.localUrl(`http://${distroHostname}/`);
2796
+
2797
+ const first = await fetch(home);
2798
+ console.log(await first.text()); // <h1>First</h1>
2799
+
2800
+ // The deploy publishes a new page, which the Distribution is still holding
2801
+ // the old version of.
2802
+ await publish("<h1>Second</h1>");
2803
+
2804
+ const stale = await fetch(home);
2805
+ console.log(await stale.text()); // <h1>First</h1>
2806
+
2807
+ const creation = await simCloudFront.createInvalidation(
2808
+ new CreateInvalidationCommand({
2809
+ DistributionId: distributionId,
2810
+ InvalidationBatch: {
2811
+ CallerReference: "deployment-1",
2812
+ Paths: { Quantity: 1, Items: ["/*"] },
2813
+ },
2814
+ }),
2815
+ );
2816
+
2817
+ console.log(creation.Invalidation!.Status); // InProgress
2818
+
2819
+ const released = await fetch(home);
2820
+ console.log(await released.text()); // <h1>Second</h1>
2821
+
2822
+ // The invalidation finishes on the background scheduler.
2823
+ await simAws.backgroundTasksComplete();
2824
+
2825
+ const invalidation = await simCloudFront.getInvalidation(
2826
+ new GetInvalidationCommand({
2827
+ DistributionId: distributionId,
2828
+ Id: creation.Invalidation!.Id,
2829
+ }),
2830
+ );
2831
+
2832
+ console.log(invalidation.Invalidation!.Status); // Completed
2833
+
2834
+ const listing = await simCloudFront.listInvalidations(
2835
+ new ListInvalidationsCommand({ DistributionId: distributionId }),
2836
+ );
2837
+
2838
+ console.log(listing.InvalidationList!.Quantity); // 1
2839
+ } finally {
2840
+ await srv.close();
2841
+ }
2842
+ ```
2843
+
2844
+ ### The paths a batch names
2845
+
2846
+ A path names one object. A path ending in a wildcard names everything below what comes before it.
2847
+ `/images/*` clears the images and leaves `/index.html` where it was, and `/*` clears everything the
2848
+ Distribution holds. A path arriving without its leading slash is read as though it had one. The
2849
+ bare `*` a console user types is the same batch as `/*`.
2850
+
2851
+ An invalidation reaches every edge. A page cached at three points of presence is cleared at all
2852
+ three, whichever edge the requests that filled them arrived at.
2853
+
2854
+ The entries go as the invalidation is created. Real CloudFront clears each point of presence over
2855
+ the following seconds, and a test waiting for that before asking again would be waiting on the
2856
+ simulator.
2857
+
2858
+ ### Reading an invalidation back
2859
+
2860
+ An invalidation starts `InProgress` and reaches `Completed` on the background scheduler, the way a
2861
+ Distribution reaches `Deployed`. `GetDistribution` counts the running ones as
2862
+ `InProgressInvalidationBatches`.
2863
+
2864
+ `GetInvalidation` answers with the batch of paths the invalidation was created from.
2865
+ `ListInvalidations` answers with the Distribution's whole list, most recently created first. An
2866
+ invalidation ID the Distribution has never held is `NoSuchInvalidation`.
2867
+
2868
+ ### Repeating a batch
2869
+
2870
+ `CallerReference` makes a batch idempotent. Sending one twice with the same paths answers with the
2871
+ invalidation that reference already created, and clears nothing a second time. Sending it with
2872
+ different paths is `InvalidationBatchAlreadyExists`.
2873
+
2874
+ ## Origin request policies
2875
+
2876
+ An origin request policy decides which of the viewer's headers, cookies and query strings a cache
2877
+ Behavior carries to its Origin. Declare one as `AWS::CloudFront::OriginRequestPolicy` and point a
2878
+ Behavior's `OriginRequestPolicyId` at it with a `Ref`, which is what CDK's `OriginRequestPolicy`
2879
+ construct synthesizes.
2880
+
2881
+ ```typescript sim-cloudfront-origin-request-policy
2882
+ /**
2883
+ * Reading back the origin request policy a Behavior was given.
2884
+ */
2885
+
2886
+ import { GetDistributionCommand } from "@aws-sdk/client-cloudfront";
2887
+ import { SimAws } from "@kensio/yulin";
2888
+
2889
+ const simAws = new SimAws();
2890
+
2891
+ const stack = await simAws.cloudFormation().deployTemplate({
2892
+ stackName: "site-stack",
2893
+ template: {
2894
+ Resources: {
2895
+ SiteBucket: {
2896
+ Type: "AWS::S3::Bucket",
2897
+ Properties: { BucketName: "site-bucket" },
2898
+ },
2899
+ BeaconPolicy: {
2900
+ Type: "AWS::CloudFront::OriginRequestPolicy",
2901
+ Properties: {
2902
+ OriginRequestPolicyConfig: {
2903
+ Name: "BeaconPolicy",
2904
+ CookiesConfig: { CookieBehavior: "none" },
2905
+ HeadersConfig: { HeaderBehavior: "none" },
2906
+ QueryStringsConfig: { QueryStringBehavior: "all" },
2907
+ },
2908
+ },
2909
+ },
2910
+ SiteDistribution: {
2911
+ Type: "AWS::CloudFront::Distribution",
2912
+ DependsOn: ["SiteBucket", "BeaconPolicy"],
2913
+ Properties: {
2914
+ DistributionConfig: {
2915
+ DefaultRootObject: "index.html",
2916
+ Origins: [
2917
+ {
2918
+ Id: "SiteOrigin",
2919
+ DomainName: "site-bucket.s3.amazonaws.com",
2920
+ S3OriginConfig: {},
2921
+ },
2922
+ ],
2923
+ DefaultCacheBehavior: {
2924
+ TargetOriginId: "SiteOrigin",
2925
+ ViewerProtocolPolicy: "allow-all",
2926
+ // CORS-S3Origin, one of CloudFront's managed policies.
2927
+ OriginRequestPolicyId: "88a5eaf4-2fd4-4709-b370-b4c650ea3fcf",
2928
+ },
2929
+ CacheBehaviors: [
2930
+ {
2931
+ PathPattern: "/beacon",
2932
+ TargetOriginId: "SiteOrigin",
2933
+ ViewerProtocolPolicy: "allow-all",
2934
+ OriginRequestPolicyId: { Ref: "BeaconPolicy" },
2935
+ },
2936
+ ],
2937
+ },
2938
+ },
2939
+ },
2940
+ },
2941
+ Outputs: {
2942
+ DistributionId: { Value: { Ref: "SiteDistribution" } },
2943
+ BeaconPolicyId: { Value: { Ref: "BeaconPolicy" } },
2944
+ },
2945
+ },
2946
+ });
2947
+
2948
+ await stack.waitForDeployComplete();
2949
+
2950
+ const read = await simAws
2951
+ .cloudFront()
2952
+ .getDistribution(
2953
+ new GetDistributionCommand({ Id: stack.output("DistributionId") }),
2954
+ );
2955
+ const config = read.Distribution?.DistributionConfig;
2956
+
2957
+ // The managed ID the default Behavior was given.
2958
+ console.log(config?.DefaultCacheBehavior?.OriginRequestPolicyId);
2959
+
2960
+ // The ID of the policy the template created, which the path Behavior Refs.
2961
+ console.log(
2962
+ config?.CacheBehaviors?.Items?.[0]?.OriginRequestPolicyId ===
2963
+ stack.output("BeaconPolicyId"),
2964
+ );
2965
+ ```
2966
+
2967
+ A Behavior records the ID it was given, and `GetDistribution` reports it back for both the default
2968
+ Behavior and a named one. An update changing the policy is reported the same way.
2969
+
2970
+ A policy name is unique within an account, as it is in CloudFront. A second
2971
+ `AWS::CloudFront::OriginRequestPolicy` claiming a name is refused with
2972
+ `OriginRequestPolicyAlreadyExists`.
2973
+
2974
+ `HeadersConfig`, `CookiesConfig` and `QueryStringsConfig` are read along with `Name` and `Comment`.
2975
+ `CookieBehavior` and `QueryStringBehavior` each take `none`, `whitelist`, `allExcept` and `all`.
2976
+ `HeaderBehavior` takes `none`, `whitelist`, `allExcept`, `allViewer` and
2977
+ `allViewerAndWhitelistCloudFront`. An absent section falls back to `none`. A section naming a
2978
+ behaviour CloudFront does not offer fails the Stack, naming the Resource.
2979
+
2980
+ ### What a custom Origin is sent
2981
+
2982
+ A custom Origin is sent the headers, cookies and query strings the Behavior's cache policy and
2983
+ origin request policy name between them, and none of the rest of the viewer's request. That union is
2984
+ what real CloudFront sends. The cache policy half is in it because an Origin has to be able to
2985
+ answer for the key its response is stored under.
2986
+
2987
+ Alongside it CloudFront sends what it sends of its own accord. `Host` is the Origin's own domain,
2988
+ whatever the policies name (a viewer's own `Host` never reaches an Origin here, so
2989
+ `AllViewerExceptHostHeader` and `AllViewer` reach a Function URL Origin alike).
2990
+ `User-Agent` is `Amazon CloudFront` unless the policies carry the viewer's own. `Accept-Encoding` is
2991
+ the normalized `gzip`, `br` or `gzip, br` the cache policy's `EnableAcceptEncoding` flags asked for.
2992
+ `Content-Length`, `Content-Type` and `Transfer-Encoding` describe the body and travel with it. The
2993
+ Origin's custom headers and its origin access control's signing headers are applied on top.
2994
+
2995
+ ```typescript sim-cloudfront-origin-request-forwarding
2996
+ /**
2997
+ * What a custom Origin reads of the viewer's request, with and without an
2998
+ * origin request policy.
2999
+ */
3000
+
3001
+ import {
3002
+ CreateApiCommand,
3003
+ CreateIntegrationCommand,
3004
+ CreateRouteCommand,
3005
+ CreateStageCommand,
3006
+ } from "@aws-sdk/client-apigatewayv2";
3007
+ import { CreateDistributionCommand } from "@aws-sdk/client-cloudfront";
3008
+ import {
3009
+ AddPermissionCommand,
3010
+ CreateFunctionCommand,
3011
+ } from "@aws-sdk/client-lambda";
3012
+
3013
+ import { SimAws } from "@kensio/yulin";
3014
+ import { makeLambdaZipFileInput } from "@kensio/yulin/lambda";
3015
+ import { serveSimAws } from "@kensio/yulin/serve";
3016
+
3017
+ const simAws = new SimAws();
3018
+
3019
+ // A function reporting the query string and the user agent it was asked with.
3020
+ const { FunctionArn } = await simAws.lambda().createFunction(
3021
+ new CreateFunctionCommand({
3022
+ FunctionName: "search",
3023
+ Role: "arn:aws:iam::111111111111:role/SearchRole",
3024
+ Code: {
3025
+ ZipFile: makeLambdaZipFileInput(
3026
+ (event: {
3027
+ rawQueryString: string;
3028
+ headers: Record<string, string>;
3029
+ }) => ({
3030
+ query: event.rawQueryString,
3031
+ userAgent: event.headers["user-agent"],
3032
+ }),
3033
+ ),
3034
+ },
3035
+ }),
3036
+ );
3037
+
3038
+ const apiGateway = simAws.apiGatewayV2();
3039
+
3040
+ const { ApiId, ApiEndpoint } = await apiGateway.createApi(
3041
+ new CreateApiCommand({ Name: "search", ProtocolType: "HTTP" }),
3042
+ );
3043
+
3044
+ const { IntegrationId } = await apiGateway.createIntegration(
3045
+ new CreateIntegrationCommand({
3046
+ ApiId,
3047
+ IntegrationType: "AWS_PROXY",
3048
+ IntegrationUri: FunctionArn,
3049
+ PayloadFormatVersion: "2.0",
3050
+ }),
3051
+ );
3052
+
3053
+ await apiGateway.createRoute(
3054
+ new CreateRouteCommand({
3055
+ ApiId,
3056
+ RouteKey: "GET /search",
3057
+ Target: `integrations/${IntegrationId}`,
3058
+ }),
3059
+ );
3060
+
3061
+ await apiGateway.createRoute(
3062
+ new CreateRouteCommand({
3063
+ ApiId,
3064
+ RouteKey: "GET /open/search",
3065
+ Target: `integrations/${IntegrationId}`,
3066
+ }),
3067
+ );
3068
+
3069
+ await apiGateway.createStage(
3070
+ new CreateStageCommand({ ApiId, StageName: "$default", AutoDeploy: true }),
3071
+ );
3072
+
3073
+ await simAws.lambda().addPermission(
3074
+ new AddPermissionCommand({
3075
+ FunctionName: "search",
3076
+ StatementId: "api-gateway-invoke",
3077
+ Action: "lambda:InvokeFunction",
3078
+ Principal: "apigateway.amazonaws.com",
3079
+ SourceArn: `arn:aws:execute-api:us-east-1:888888888888:${ApiId}/*/*`,
3080
+ }),
3081
+ );
3082
+
3083
+ // Two Behaviors on the same Origin. The default names no policy, and /open/*
3084
+ // names AllViewer, one of CloudFront's managed policies.
3085
+ const distributionCreation = await simAws.cloudFront().createDistribution(
3086
+ new CreateDistributionCommand({
3087
+ DistributionConfig: {
3088
+ CallerReference: "search-site",
3089
+ Comment: "Search CDN",
3090
+ Enabled: true,
3091
+ Origins: {
3092
+ Quantity: 1,
3093
+ Items: [
3094
+ {
3095
+ Id: "api-origin",
3096
+ DomainName: new URL(ApiEndpoint).hostname,
3097
+ CustomOriginConfig: {
3098
+ HTTPPort: 80,
3099
+ HTTPSPort: 443,
3100
+ OriginProtocolPolicy: "https-only",
3101
+ },
3102
+ },
3103
+ ],
3104
+ },
3105
+ DefaultCacheBehavior: {
3106
+ TargetOriginId: "api-origin",
3107
+ ViewerProtocolPolicy: "allow-all",
3108
+ },
3109
+ CacheBehaviors: {
3110
+ Quantity: 1,
3111
+ Items: [
3112
+ {
3113
+ PathPattern: "/open/*",
3114
+ TargetOriginId: "api-origin",
3115
+ ViewerProtocolPolicy: "allow-all",
3116
+ OriginRequestPolicyId: "216adef6-5c7f-47e4-b989-5492eafa07d3",
3117
+ },
3118
+ ],
3119
+ },
3120
+ },
3121
+ }),
3122
+ );
3123
+
3124
+ const distroHostname = distributionCreation.Distribution!.DomainName!;
3125
+ const srv = await serveSimAws({ simAws });
3126
+
3127
+ try {
3128
+ const withheld = await fetch(
3129
+ srv.localUrl(`http://${distroHostname}/search?q=kettle`),
3130
+ { headers: { "user-agent": "Firefox" } },
3131
+ );
3132
+
3133
+ // {"query":"","userAgent":"Amazon CloudFront"}
3134
+ console.log(await withheld.text());
3135
+
3136
+ const forwarded = await fetch(
3137
+ srv.localUrl(`http://${distroHostname}/open/search?q=kettle`),
3138
+ { headers: { "user-agent": "Firefox" } },
3139
+ );
3140
+
3141
+ // {"query":"q=kettle","userAgent":"Firefox"}
3142
+ console.log(await forwarded.text());
3143
+ } finally {
3144
+ await srv.close();
3145
+ }
3146
+ ```
3147
+
3148
+ A Behavior naming neither policy sends the path and nothing else. That is a Distribution CloudFront
3149
+ would serve the same way, and an Origin reading a query string behind one is a bug worth a failing
3150
+ test.
3151
+
3152
+ An S3 Origin is unaffected. It reads its Bucket through GetObject and builds no request to narrow.
3153
+
3154
+ ### Managed origin request policies
3155
+
3156
+ CloudFront's eight managed policies are here from the start, under the IDs AWS publishes, and a
3157
+ Behavior names one without a template creating anything. `AllViewer`
3158
+ (`216adef6-5c7f-47e4-b989-5492eafa07d3`), `AllViewerAndCloudFrontHeaders-2022-06`
3159
+ (`33f36d7e-f396-46d9-90e0-52428a34d9dc`), `AllViewerExceptHostHeader`
3160
+ (`b689b0a8-53d0-40ab-baf2-68738e2966ac`), `CORS-CustomOrigin`
3161
+ (`59781a5b-3903-41f3-afcb-af62929ccde1`), `CORS-S3Origin` (`88a5eaf4-2fd4-4709-b370-b4c650ea3fcf`),
3162
+ `Elemental-MediaTailor-PersonalizedManifests` (`775133bc-15f2-49f9-abea-afb2e0bf67d2`),
3163
+ `HostHeaderOnly` (`bf0718e1-ba1e-49d1-88b1-f726733018ae`) and `UserAgentRefererHeaders`
3164
+ (`acba4595-bd28-49b8-b9fe-13317c0390fa`) are each held under the name
3165
+ [AWS publishes](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html)
3166
+ for it. CDK's `OriginRequestPolicy.ALL_VIEWER` and its seven siblings synthesize those IDs. A stack
3167
+ reaching for one deploys.
3168
+
3169
+ Each also carries the three sections AWS publishes for it. A Behavior on `AllViewer` here sends the
3170
+ Origin everything the viewer sent bar its `Host`, which is the Origin's own domain under every
3171
+ policy. One on `CORS-CustomOrigin` sends the `Origin` header alone. One on
3172
+ `AllViewerExceptHostHeader` sends what `AllViewer` sends, since the `Host` it withholds was never
3173
+ the viewer's here.
3174
+
3175
+ The managed policies sit in CloudFront's own namespace. A template may create a policy called
3176
+ `AllViewer` of its own, and deleting that stack leaves the managed one where it was.
3177
+
3178
+ A CloudFormation Distribution whose Behavior names a policy that is neither managed nor created here
3179
+ deploys without one. The `OriginRequestPolicyId` lands on `stack.ignoredProperties` under that
3180
+ Behavior, the way an absent cache policy does, and the Behavior reports no policy.
3181
+
3182
+ `CreateDistribution` and `UpdateDistribution` still refuse the same ID with
3183
+ `NoSuchOriginRequestPolicy`, as real CloudFront refuses it.
3184
+
2327
3185
  ## Origin access controls
2328
3186
 
2329
3187
  An origin access control is how a Distribution authenticates to a private Origin. The Origin then
@@ -2945,6 +3803,12 @@ Sim CloudFront currently supports:
2945
3803
  - CloudFront Functions reading an associated key value store through `cf.kvs()`
2946
3804
  - `AWS::CloudFront::ResponseHeadersPolicy`, for headers a cache Behavior sets on every response
2947
3805
  - `AWS::CloudFront::CachePolicy`, and a Behavior's `CachePolicyId` read back through `GetDistribution`
3806
+ - A cache on each Distribution, keyed on the Behavior's cache policy and on the edge the request
3807
+ arrived at, expiring on the simulation's clock
3808
+ - `CreateInvalidationCommand`, `GetInvalidationCommand` and `ListInvalidationsCommand`, clearing
3809
+ what a Distribution holds and reading the batches back
3810
+ - `AWS::CloudFront::OriginRequestPolicy`, and a Behavior's `OriginRequestPolicyId` read back the
3811
+ same way
2948
3812
  - `AWS::CloudFront::KeyValueStore`, and `KeyValueStoreAssociations` on `AWS::CloudFront::Function`
2949
3813
  - `AWS::CloudFront::OriginAccessControl`, letting an Origin read a private Bucket as CloudFront
2950
3814
  - Viewer certificates from sim ACM, including CloudFront's `us-east-1` requirement
@@ -2959,12 +3823,27 @@ whether the simulator needs them to model the requested behaviour safely.
2959
3823
 
2960
3824
  Where sim CloudFront knowingly behaves differently from AWS:
2961
3825
 
2962
- - **The origin events run on every request that reaches the Origin.** Real CloudFront runs
2963
- `origin-request` and `origin-response` on a cache miss, and serves a cache hit without reaching
2964
- either. Simulated CloudFront holds no cache, and every request that gets as far as the Origin is a
2965
- miss here. A request a web ACL blocked or a viewer-request function answered reaches neither
2966
- event, and an `origin-request` function that returns a response leaves the Origin unread with no
2967
- `origin-response` event after it.
3826
+ - **An expired entry is fetched again rather than revalidated.** Real CloudFront asks the Origin
3827
+ whether the object has changed and takes a `304 Not Modified` as permission to carry on serving
3828
+ what it holds. Here the expired entry is dropped and the Origin's next answer replaces it.
3829
+ `Stale-While-Revalidate` and `Stale-If-Error` are read as no directive at all. Nothing stale is
3830
+ ever served.
3831
+ - **A cached entry stays until it expires or an invalidation clears it.** Nothing evicts one to make
3832
+ room.
3833
+ - **`X-Cache` says Hit or Miss and nothing else.** Real CloudFront also reports `RefreshHit`,
3834
+ `Error`, `Redirect`, `LambdaGeneratedResponse` and `FunctionGeneratedResponse` there. A response
3835
+ answered before the cache was reached (one a web ACL blocked, or one a viewer-request function
3836
+ returned) carries no `X-Cache` at all.
3837
+ - **An invalidation listing is never paged.** `ListInvalidations` echoes the `Marker` and `MaxItems`
3838
+ it was sent and answers with every invalidation the Distribution holds. `IsTruncated` is always
3839
+ false and no `NextMarker` comes back. Real CloudFront pages at 100.
3840
+ - **A Behavior with no cache policy caches nothing.** Real CloudFront falls back to the legacy
3841
+ `ForwardedValues` and the TTLs beside it, and sim CloudFront skips both. Give the Behavior a
3842
+ `CachePolicyId`, as CDK and the console both do.
3843
+ - **Every error status is held for its error TTL.** Real CloudFront caches 404, 414, 500, 501, 502,
3844
+ 503 and 504, and caches 400, 403 and 405 only where the Origin sent a `Cache-Control max-age` or
3845
+ `s-maxage` header. It then holds the error for the longer of that header and `ErrorCachingMinTTL`.
3846
+ Here every status of 400 and above is held for `ErrorCachingMinTTL` alone.
2968
3847
  - **An Origin keeps its kind and its Bucket through an origin-request function.** Real CloudFront
2969
3848
  lets a handler hand back `origin.s3` where it was given `origin.custom`, or point an S3 Origin at
2970
3849
  another Bucket. Both need something a simulated Origin does not hold, the dispatcher that reaches
@@ -3087,12 +3966,11 @@ Where sim CloudFront knowingly behaves differently from AWS:
3087
3966
  share of real responses carry `Server-Timing`. This simulation adds it to every response once
3088
3967
  `Enabled` is true. A test asserting on it never depends on chance. The header's value is a
3089
3968
  fixed placeholder, since nothing here measures an Origin fetch the way CloudFront's edge does.
3090
- - **A cache policy is recorded and never applied.** Sim CloudFront models no edge caching. A
3091
- Behavior's `CachePolicyId` is checked against the policies this simulation holds and reported
3092
- back, and the TTLs, the cache key and the compression settings behind it decide nothing. Every
3093
- request reaches the Origin, whatever the policy would have cached on real CloudFront.
3094
- - **A cache policy carries its name and its comment, and nothing else.** The TTLs and
3095
- `ParametersInCacheKeyAndForwardedToOrigin` of an `AWS::CloudFront::CachePolicy` are read past,
3096
- since nothing here would act on them.
3097
- - **`OriginRequestPolicyId` is accepted and ignored.** A Behavior's origin request policy is left
3098
- unvalidated, and `AWS::CloudFront::OriginRequestPolicy` is skipped.
3969
+ - **A viewer's `Host` header never reaches an Origin.** Real CloudFront forwards it where a policy
3970
+ names it, which is what `AllViewerExceptHostHeader` exists to stop. Here an Origin request always
3971
+ carries the Origin's own domain as `Host`, since the request has to reach the simulated service
3972
+ its URL names.
3973
+ - **CloudFront's own headers are not generated.** `X-Amz-Cf-Id`, `Via`, `X-Forwarded-For` and the
3974
+ `CloudFront-Viewer-*` family are absent from an Origin request, so a policy naming one of them
3975
+ forwards nothing. `Host`, `User-Agent` and the normalized `Accept-Encoding` are the three this
3976
+ simulation sends of its own accord.