1use chrono::{DateTime, Utc};
4use rustack_cloudfront_model::{
5 CLOUDFRONT_XML_NAMESPACE, CachePolicy, CachePolicyConfig, CloudFrontFunction,
6 CloudFrontOriginAccessIdentity, CloudFrontOriginAccessIdentityConfig, CustomErrorResponse,
7 CustomHeader, Distribution, DistributionConfig, FieldLevelEncryption,
8 FieldLevelEncryptionProfile, FunctionConfig, Invalidation, KeyGroup, KeyValueStore, Origin,
9 OriginAccessControl, OriginAccessControlConfig, OriginRequestPolicy, OriginRequestPolicyConfig,
10 PublicKey, RealtimeLogConfig, ResponseHeadersPolicy, ResponseHeadersPolicyConfig, TagSet,
11};
12
13use super::XmlWriter;
14
15pub fn iso8601(ts: &DateTime<Utc>) -> String {
17 ts.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string()
18}
19
20pub fn write_distribution_config(w: &mut XmlWriter, cfg: &DistributionConfig, element_name: &str) {
26 w.open(element_name);
27 w.element("CallerReference", &cfg.caller_reference);
28 write_string_list(w, "Aliases", "CNAME", &cfg.aliases);
29 w.element("DefaultRootObject", &cfg.default_root_object);
30 write_origins(w, &cfg.origins);
31 write_origin_groups(w, &cfg.origin_groups);
32 write_default_cache_behavior(w, &cfg.default_cache_behavior);
33 write_cache_behaviors(w, &cfg.cache_behaviors);
34 write_custom_error_responses(w, &cfg.custom_error_responses);
35 w.element("Comment", &cfg.comment);
36 write_logging(w, &cfg);
37 w.optional_str("PriceClass", &cfg.price_class);
38 w.bool("Enabled", cfg.enabled);
39 write_viewer_certificate(w, cfg);
40 write_restrictions(w, cfg);
41 w.optional_str("WebACLId", &cfg.web_acl_id);
42 w.optional_str("HttpVersion", &cfg.http_version);
43 w.bool("IsIPV6Enabled", cfg.is_ipv6_enabled);
44 w.optional_str(
45 "ContinuousDeploymentPolicyId",
46 &cfg.continuous_deployment_policy_id,
47 );
48 w.bool("Staging", cfg.staging);
49 w.optional_str("AnycastIpListId", &cfg.anycast_ip_list_id);
50 w.optional_str("ConnectionMode", &cfg.connection_mode);
51 w.close(element_name);
52}
53
54fn write_string_list(w: &mut XmlWriter, wrapper: &str, item_name: &str, items: &[String]) {
55 w.open(wrapper);
56 w.element_display("Quantity", items.len());
57 if !items.is_empty() {
58 w.open("Items");
59 for it in items {
60 w.element(item_name, it);
61 }
62 w.close("Items");
63 }
64 w.close(wrapper);
65}
66
67fn write_origins(w: &mut XmlWriter, origins: &[Origin]) {
68 w.open("Origins");
69 w.element_display("Quantity", origins.len());
70 if !origins.is_empty() {
71 w.open("Items");
72 for o in origins {
73 write_origin(w, o);
74 }
75 w.close("Items");
76 }
77 w.close("Origins");
78}
79
80fn write_origin(w: &mut XmlWriter, o: &Origin) {
81 w.open("Origin");
82 w.element("Id", &o.id);
83 w.element("DomainName", &o.domain_name);
84 w.element("OriginPath", &o.origin_path);
85 write_custom_header_list(w, &o.custom_headers);
86 if let Some(s3) = &o.s3_origin_config {
87 w.open("S3OriginConfig");
88 w.element("OriginAccessIdentity", &s3.origin_access_identity);
89 w.close("S3OriginConfig");
90 }
91 if let Some(c) = &o.custom_origin_config {
92 w.open("CustomOriginConfig");
93 w.element_display("HTTPPort", c.http_port);
94 w.element_display("HTTPSPort", c.https_port);
95 w.element("OriginProtocolPolicy", &c.origin_protocol_policy);
96 write_string_list(
97 w,
98 "OriginSslProtocols",
99 "SslProtocol",
100 &c.origin_ssl_protocols,
101 );
102 w.element_display("OriginReadTimeout", c.origin_read_timeout);
103 w.element_display("OriginKeepaliveTimeout", c.origin_keepalive_timeout);
104 w.close("CustomOriginConfig");
105 }
106 w.element_display(
107 "ConnectionAttempts",
108 if o.connection_attempts == 0 {
109 3
110 } else {
111 o.connection_attempts
112 },
113 );
114 w.element_display(
115 "ConnectionTimeout",
116 if o.connection_timeout == 0 {
117 10
118 } else {
119 o.connection_timeout
120 },
121 );
122 if let Some(os) = &o.origin_shield {
123 w.open("OriginShield");
124 w.bool("Enabled", os.enabled);
125 w.optional_str("OriginShieldRegion", &os.origin_shield_region);
126 w.close("OriginShield");
127 }
128 w.element("OriginAccessControlId", &o.origin_access_control_id);
129 w.close("Origin");
130}
131
132fn write_custom_header_list(w: &mut XmlWriter, items: &[CustomHeader]) {
133 w.open("CustomHeaders");
134 w.element_display("Quantity", items.len());
135 if !items.is_empty() {
136 w.open("Items");
137 for h in items {
138 w.open("OriginCustomHeader");
139 w.element("HeaderName", &h.header_name);
140 w.element("HeaderValue", &h.header_value);
141 w.close("OriginCustomHeader");
142 }
143 w.close("Items");
144 }
145 w.close("CustomHeaders");
146}
147
148fn write_origin_groups(w: &mut XmlWriter, groups: &[rustack_cloudfront_model::OriginGroup]) {
149 w.open("OriginGroups");
150 w.element_display("Quantity", groups.len());
151 if !groups.is_empty() {
152 w.open("Items");
153 for g in groups {
154 w.open("OriginGroup");
155 w.element("Id", &g.id);
156 w.open("FailoverCriteria");
157 write_i32_list(w, "StatusCodes", "StatusCode", &g.failover_status_codes);
158 w.close("FailoverCriteria");
159 write_string_list(w, "Members", "OriginGroupMember", &g.member_origins);
160 w.optional_str("SelectionCriteria", &g.selection_criteria);
161 w.close("OriginGroup");
162 }
163 w.close("Items");
164 }
165 w.close("OriginGroups");
166}
167
168fn write_i32_list(w: &mut XmlWriter, wrapper: &str, item_name: &str, items: &[i32]) {
169 w.open(wrapper);
170 w.element_display("Quantity", items.len());
171 if !items.is_empty() {
172 w.open("Items");
173 for it in items {
174 w.element_display(item_name, it);
175 }
176 w.close("Items");
177 }
178 w.close(wrapper);
179}
180
181fn write_default_cache_behavior(w: &mut XmlWriter, cb: &rustack_cloudfront_model::CacheBehavior) {
182 w.open("DefaultCacheBehavior");
183 write_cache_behavior_common(w, cb);
184 w.close("DefaultCacheBehavior");
185}
186
187fn write_cache_behaviors(w: &mut XmlWriter, cbs: &[rustack_cloudfront_model::CacheBehavior]) {
188 w.open("CacheBehaviors");
189 w.element_display("Quantity", cbs.len());
190 if !cbs.is_empty() {
191 w.open("Items");
192 for cb in cbs {
193 w.open("CacheBehavior");
194 w.element("PathPattern", &cb.path_pattern);
195 write_cache_behavior_common(w, cb);
196 w.close("CacheBehavior");
197 }
198 w.close("Items");
199 }
200 w.close("CacheBehaviors");
201}
202
203fn write_cache_behavior_common(w: &mut XmlWriter, cb: &rustack_cloudfront_model::CacheBehavior) {
204 w.element("TargetOriginId", &cb.target_origin_id);
205 w.open("TrustedSigners");
206 w.bool("Enabled", cb.trusted_signers_enabled);
207 w.element_display("Quantity", cb.trusted_signers.len());
208 if !cb.trusted_signers.is_empty() {
209 w.open("Items");
210 for s in &cb.trusted_signers {
211 w.element("AwsAccountNumber", s);
212 }
213 w.close("Items");
214 }
215 w.close("TrustedSigners");
216 w.open("TrustedKeyGroups");
217 w.bool("Enabled", cb.trusted_key_groups_enabled);
218 w.element_display("Quantity", cb.trusted_key_groups.len());
219 if !cb.trusted_key_groups.is_empty() {
220 w.open("Items");
221 for k in &cb.trusted_key_groups {
222 w.element("KeyGroup", k);
223 }
224 w.close("Items");
225 }
226 w.close("TrustedKeyGroups");
227 w.element("ViewerProtocolPolicy", &cb.viewer_protocol_policy);
228 write_allowed_methods(w, &cb.allowed_methods, &cb.cached_methods);
229 w.bool("SmoothStreaming", cb.smooth_streaming);
230 w.bool("Compress", cb.compress);
231 write_lambda_associations(w, &cb.lambda_function_associations);
232 write_function_associations(w, &cb.function_associations);
233 w.optional_str("FieldLevelEncryptionId", &cb.field_level_encryption_id);
234 w.optional_str("RealtimeLogConfigArn", &cb.realtime_log_config_arn);
235 w.optional_str("CachePolicyId", &cb.cache_policy_id);
236 w.optional_str("OriginRequestPolicyId", &cb.origin_request_policy_id);
237 w.optional_str("ResponseHeadersPolicyId", &cb.response_headers_policy_id);
238 if cb.grpc_enabled {
239 w.open("GrpcConfig");
240 w.bool("Enabled", true);
241 w.close("GrpcConfig");
242 }
243 if let Some(fv) = &cb.forwarded_values {
244 w.open("ForwardedValues");
245 w.bool("QueryString", fv.query_string);
246 w.open("Cookies");
247 w.element("Forward", &fv.cookies.forward);
248 if !fv.cookies.whitelisted_names.is_empty() {
249 write_string_list(w, "WhitelistedNames", "Name", &fv.cookies.whitelisted_names);
250 }
251 w.close("Cookies");
252 write_string_list(w, "Headers", "Name", &fv.headers);
253 write_string_list(
254 w,
255 "QueryStringCacheKeys",
256 "Name",
257 &fv.query_string_cache_keys,
258 );
259 w.close("ForwardedValues");
260 }
261 w.element_display("MinTTL", cb.min_ttl);
262 w.element_display("DefaultTTL", cb.default_ttl);
263 w.element_display("MaxTTL", cb.max_ttl);
264}
265
266fn write_allowed_methods(w: &mut XmlWriter, allowed: &[String], cached: &[String]) {
267 w.open("AllowedMethods");
268 w.element_display("Quantity", allowed.len());
269 if !allowed.is_empty() {
270 w.open("Items");
271 for m in allowed {
272 w.element("Method", m);
273 }
274 w.close("Items");
275 }
276 w.open("CachedMethods");
277 w.element_display("Quantity", cached.len());
278 if !cached.is_empty() {
279 w.open("Items");
280 for m in cached {
281 w.element("Method", m);
282 }
283 w.close("Items");
284 }
285 w.close("CachedMethods");
286 w.close("AllowedMethods");
287}
288
289fn write_lambda_associations(
290 w: &mut XmlWriter,
291 items: &[rustack_cloudfront_model::LambdaFunctionAssociation],
292) {
293 w.open("LambdaFunctionAssociations");
294 w.element_display("Quantity", items.len());
295 if !items.is_empty() {
296 w.open("Items");
297 for l in items {
298 w.open("LambdaFunctionAssociation");
299 w.element("LambdaFunctionARN", &l.lambda_function_arn);
300 w.element("EventType", &l.event_type);
301 w.bool("IncludeBody", l.include_body);
302 w.close("LambdaFunctionAssociation");
303 }
304 w.close("Items");
305 }
306 w.close("LambdaFunctionAssociations");
307}
308
309fn write_function_associations(
310 w: &mut XmlWriter,
311 items: &[rustack_cloudfront_model::FunctionAssociation],
312) {
313 w.open("FunctionAssociations");
314 w.element_display("Quantity", items.len());
315 if !items.is_empty() {
316 w.open("Items");
317 for f in items {
318 w.open("FunctionAssociation");
319 w.element("FunctionARN", &f.function_arn);
320 w.element("EventType", &f.event_type);
321 w.close("FunctionAssociation");
322 }
323 w.close("Items");
324 }
325 w.close("FunctionAssociations");
326}
327
328fn write_custom_error_responses(w: &mut XmlWriter, items: &[CustomErrorResponse]) {
329 w.open("CustomErrorResponses");
330 w.element_display("Quantity", items.len());
331 if !items.is_empty() {
332 w.open("Items");
333 for c in items {
334 w.open("CustomErrorResponse");
335 w.element_display("ErrorCode", c.error_code);
336 w.optional_str("ResponsePagePath", &c.response_page_path);
337 w.optional_str("ResponseCode", &c.response_code);
338 w.element_display("ErrorCachingMinTTL", c.error_caching_min_ttl);
339 w.close("CustomErrorResponse");
340 }
341 w.close("Items");
342 }
343 w.close("CustomErrorResponses");
344}
345
346fn write_logging(w: &mut XmlWriter, cfg: &DistributionConfig) {
347 w.open("Logging");
348 w.bool("Enabled", cfg.logging.enabled);
349 w.bool("IncludeCookies", cfg.logging.include_cookies);
350 w.element("Bucket", &cfg.logging.bucket);
351 w.element("Prefix", &cfg.logging.prefix);
352 w.close("Logging");
353}
354
355fn write_viewer_certificate(w: &mut XmlWriter, cfg: &DistributionConfig) {
356 let vc = &cfg.viewer_certificate;
357 w.open("ViewerCertificate");
358 w.bool(
359 "CloudFrontDefaultCertificate",
360 vc.cloud_front_default_certificate
361 || !vc.acm_certificate_arn.is_empty()
362 || !vc.iam_certificate_id.is_empty()
363 || vc.cloud_front_default_certificate,
364 );
365 w.optional_str("IAMCertificateId", &vc.iam_certificate_id);
366 w.optional_str("ACMCertificateArn", &vc.acm_certificate_arn);
367 w.optional_str("SSLSupportMethod", &vc.ssl_support_method);
368 w.optional_str("MinimumProtocolVersion", &vc.minimum_protocol_version);
369 w.optional_str("Certificate", &vc.certificate);
370 w.optional_str("CertificateSource", &vc.certificate_source);
371 w.close("ViewerCertificate");
372}
373
374fn write_restrictions(w: &mut XmlWriter, cfg: &DistributionConfig) {
375 w.open("Restrictions");
376 w.open("GeoRestriction");
377 w.element(
378 "RestrictionType",
379 if cfg.restrictions.geo_restriction.restriction_type.is_empty() {
380 "none"
381 } else {
382 &cfg.restrictions.geo_restriction.restriction_type
383 },
384 );
385 write_string_list(
386 w,
387 "Items",
388 "Location",
389 &cfg.restrictions.geo_restriction.locations,
390 );
391 w.close("GeoRestriction");
392 w.close("Restrictions");
393}
394
395#[must_use]
401pub fn distribution_xml(d: &Distribution) -> String {
402 let mut w = XmlWriter::new();
403 w.declaration();
404 w.open_root("Distribution", Some(CLOUDFRONT_XML_NAMESPACE));
405 w.element("Id", &d.id);
406 w.element("ARN", &d.arn);
407 w.element("Status", d.status.as_wire());
408 w.element("LastModifiedTime", &iso8601(&d.last_modified_time));
409 w.element_display(
410 "InProgressInvalidationBatches",
411 d.in_progress_invalidation_batches,
412 );
413 w.element("DomainName", &d.domain_name);
414 w.open("ActiveTrustedSigners");
415 w.bool("Enabled", d.active_trusted_signers_enabled);
416 w.element_display("Quantity", 0);
417 w.close("ActiveTrustedSigners");
418 w.open("ActiveTrustedKeyGroups");
419 w.bool("Enabled", d.active_trusted_key_groups_enabled);
420 w.element_display("Quantity", 0);
421 w.close("ActiveTrustedKeyGroups");
422 write_distribution_config(&mut w, &d.config, "DistributionConfig");
423 w.close("Distribution");
424 w.finish()
425}
426
427#[must_use]
429pub fn distribution_config_xml(cfg: &DistributionConfig) -> String {
430 let mut w = XmlWriter::new();
431 w.declaration();
432 w.buf_mut_push_namespace_open("DistributionConfig");
433 write_distribution_config_body(&mut w, cfg);
434 w.close("DistributionConfig");
435 w.finish()
436}
437
438#[must_use]
440pub fn distribution_list_xml(items: &[Distribution], max_items: i32) -> String {
441 let mut w = XmlWriter::new();
442 w.declaration();
443 w.open_root("DistributionList", Some(CLOUDFRONT_XML_NAMESPACE));
444 w.element("Marker", "");
445 w.element_display("MaxItems", max_items);
446 w.bool("IsTruncated", false);
447 w.element_display("Quantity", items.len());
448 if !items.is_empty() {
449 w.open("Items");
450 for d in items {
451 w.open("DistributionSummary");
452 w.element("Id", &d.id);
453 w.element("ARN", &d.arn);
454 w.element("Status", d.status.as_wire());
455 w.element("LastModifiedTime", &iso8601(&d.last_modified_time));
456 w.element("DomainName", &d.domain_name);
457 write_string_list(&mut w, "Aliases", "CNAME", &d.config.aliases);
458 write_origins(&mut w, &d.config.origins);
459 write_origin_groups(&mut w, &d.config.origin_groups);
460 write_default_cache_behavior(&mut w, &d.config.default_cache_behavior);
461 write_cache_behaviors(&mut w, &d.config.cache_behaviors);
462 write_custom_error_responses(&mut w, &d.config.custom_error_responses);
463 w.element("Comment", &d.config.comment);
464 w.optional_str("PriceClass", &d.config.price_class);
465 w.bool("Enabled", d.config.enabled);
466 write_viewer_certificate(&mut w, &d.config);
467 write_restrictions(&mut w, &d.config);
468 w.optional_str("WebACLId", &d.config.web_acl_id);
469 w.optional_str("HttpVersion", &d.config.http_version);
470 w.bool("IsIPV6Enabled", d.config.is_ipv6_enabled);
471 w.bool("Staging", d.config.staging);
472 w.close("DistributionSummary");
473 }
474 w.close("Items");
475 }
476 w.close("DistributionList");
477 w.finish()
478}
479
480#[must_use]
486pub fn invalidation_xml(inv: &Invalidation) -> String {
487 let mut w = XmlWriter::new();
488 w.declaration();
489 w.open_root("Invalidation", Some(CLOUDFRONT_XML_NAMESPACE));
490 w.element("Id", &inv.id);
491 w.element("Status", inv.status.as_wire());
492 w.element("CreateTime", &iso8601(&inv.create_time));
493 w.open("InvalidationBatch");
494 write_string_list(&mut w, "Paths", "Path", &inv.batch.paths);
495 w.element("CallerReference", &inv.batch.caller_reference);
496 w.close("InvalidationBatch");
497 w.close("Invalidation");
498 w.finish()
499}
500
501#[must_use]
503pub fn invalidation_list_xml(items: &[Invalidation], max_items: i32) -> String {
504 let mut w = XmlWriter::new();
505 w.declaration();
506 w.open_root("InvalidationList", Some(CLOUDFRONT_XML_NAMESPACE));
507 w.element("Marker", "");
508 w.element_display("MaxItems", max_items);
509 w.bool("IsTruncated", false);
510 w.element_display("Quantity", items.len());
511 if !items.is_empty() {
512 w.open("Items");
513 for inv in items {
514 w.open("InvalidationSummary");
515 w.element("Id", &inv.id);
516 w.element("CreateTime", &iso8601(&inv.create_time));
517 w.element("Status", inv.status.as_wire());
518 w.close("InvalidationSummary");
519 }
520 w.close("Items");
521 }
522 w.close("InvalidationList");
523 w.finish()
524}
525
526#[must_use]
532pub fn oac_xml(o: &OriginAccessControl) -> String {
533 let mut w = XmlWriter::new();
534 w.declaration();
535 w.open_root("OriginAccessControl", Some(CLOUDFRONT_XML_NAMESPACE));
536 w.element("Id", &o.id);
537 write_oac_config(&mut w, &o.config, "OriginAccessControlConfig");
538 w.close("OriginAccessControl");
539 w.finish()
540}
541
542#[must_use]
544pub fn oac_config_xml(cfg: &OriginAccessControlConfig) -> String {
545 let mut w = XmlWriter::new();
546 w.declaration();
547 write_oac_config_root(&mut w, cfg);
548 w.finish()
549}
550
551fn write_oac_config_root(w: &mut XmlWriter, cfg: &OriginAccessControlConfig) {
552 w.open_root("OriginAccessControlConfig", Some(CLOUDFRONT_XML_NAMESPACE));
553 write_oac_config_body(w, cfg);
554 w.close("OriginAccessControlConfig");
555}
556
557fn write_oac_config(w: &mut XmlWriter, cfg: &OriginAccessControlConfig, el: &str) {
558 w.open(el);
559 write_oac_config_body(w, cfg);
560 w.close(el);
561}
562
563fn write_oac_config_body(w: &mut XmlWriter, cfg: &OriginAccessControlConfig) {
564 w.element("Name", &cfg.name);
565 w.optional_str("Description", &cfg.description);
566 w.element("SigningProtocol", &cfg.signing_protocol);
567 w.element("SigningBehavior", &cfg.signing_behavior);
568 w.element(
569 "OriginAccessControlOriginType",
570 &cfg.origin_access_control_origin_type,
571 );
572}
573
574#[must_use]
576pub fn oac_list_xml(items: &[OriginAccessControl], max_items: i32) -> String {
577 let mut w = XmlWriter::new();
578 w.declaration();
579 w.open_root("OriginAccessControlList", Some(CLOUDFRONT_XML_NAMESPACE));
580 w.element("Marker", "");
581 w.element_display("MaxItems", max_items);
582 w.bool("IsTruncated", false);
583 w.element_display("Quantity", items.len());
584 if !items.is_empty() {
585 w.open("Items");
586 for o in items {
587 w.open("OriginAccessControlSummary");
588 w.element("Id", &o.id);
589 w.element("Name", &o.config.name);
590 w.element("Description", &o.config.description);
591 w.element("SigningProtocol", &o.config.signing_protocol);
592 w.element("SigningBehavior", &o.config.signing_behavior);
593 w.element(
594 "OriginAccessControlOriginType",
595 &o.config.origin_access_control_origin_type,
596 );
597 w.close("OriginAccessControlSummary");
598 }
599 w.close("Items");
600 }
601 w.close("OriginAccessControlList");
602 w.finish()
603}
604
605#[must_use]
611pub fn oai_xml(o: &CloudFrontOriginAccessIdentity) -> String {
612 let mut w = XmlWriter::new();
613 w.declaration();
614 w.open_root(
615 "CloudFrontOriginAccessIdentity",
616 Some(CLOUDFRONT_XML_NAMESPACE),
617 );
618 w.element("Id", &o.id);
619 w.element("S3CanonicalUserId", &o.s3_canonical_user_id);
620 w.open("CloudFrontOriginAccessIdentityConfig");
621 w.element("CallerReference", &o.config.caller_reference);
622 w.element("Comment", &o.config.comment);
623 w.close("CloudFrontOriginAccessIdentityConfig");
624 w.close("CloudFrontOriginAccessIdentity");
625 w.finish()
626}
627
628#[must_use]
630pub fn oai_config_xml(cfg: &CloudFrontOriginAccessIdentityConfig) -> String {
631 let mut w = XmlWriter::new();
632 w.declaration();
633 w.open_root(
634 "CloudFrontOriginAccessIdentityConfig",
635 Some(CLOUDFRONT_XML_NAMESPACE),
636 );
637 w.element("CallerReference", &cfg.caller_reference);
638 w.element("Comment", &cfg.comment);
639 w.close("CloudFrontOriginAccessIdentityConfig");
640 w.finish()
641}
642
643#[must_use]
645pub fn oai_list_xml(items: &[CloudFrontOriginAccessIdentity], max_items: i32) -> String {
646 let mut w = XmlWriter::new();
647 w.declaration();
648 w.open_root(
649 "CloudFrontOriginAccessIdentityList",
650 Some(CLOUDFRONT_XML_NAMESPACE),
651 );
652 w.element("Marker", "");
653 w.element_display("MaxItems", max_items);
654 w.bool("IsTruncated", false);
655 w.element_display("Quantity", items.len());
656 if !items.is_empty() {
657 w.open("Items");
658 for o in items {
659 w.open("CloudFrontOriginAccessIdentitySummary");
660 w.element("Id", &o.id);
661 w.element("S3CanonicalUserId", &o.s3_canonical_user_id);
662 w.element("Comment", &o.config.comment);
663 w.close("CloudFrontOriginAccessIdentitySummary");
664 }
665 w.close("Items");
666 }
667 w.close("CloudFrontOriginAccessIdentityList");
668 w.finish()
669}
670
671#[must_use]
677pub fn cache_policy_xml(p: &CachePolicy) -> String {
678 let mut w = XmlWriter::new();
679 w.declaration();
680 w.open_root("CachePolicy", Some(CLOUDFRONT_XML_NAMESPACE));
681 w.element("Id", &p.id);
682 w.element("LastModifiedTime", &iso8601(&p.last_modified_time));
683 w.open("CachePolicyConfig");
684 write_cache_policy_config_body(&mut w, &p.config);
685 w.close("CachePolicyConfig");
686 w.close("CachePolicy");
687 w.finish()
688}
689
690#[must_use]
692pub fn cache_policy_config_xml(cfg: &CachePolicyConfig) -> String {
693 let mut w = XmlWriter::new();
694 w.declaration();
695 w.open_root("CachePolicyConfig", Some(CLOUDFRONT_XML_NAMESPACE));
696 write_cache_policy_config_body(&mut w, cfg);
697 w.close("CachePolicyConfig");
698 w.finish()
699}
700
701fn write_cache_policy_config_body(w: &mut XmlWriter, cfg: &CachePolicyConfig) {
702 w.optional_str("Comment", &cfg.comment);
703 w.element("Name", &cfg.name);
704 w.element_display("DefaultTTL", cfg.default_ttl);
705 w.element_display("MaxTTL", cfg.max_ttl);
706 w.element_display("MinTTL", cfg.min_ttl);
707 w.open("ParametersInCacheKeyAndForwardedToOrigin");
708 let p = &cfg.parameters_in_cache_key_and_forwarded_to_origin;
709 w.bool("EnableAcceptEncodingGzip", p.enable_accept_encoding_gzip);
710 w.bool(
711 "EnableAcceptEncodingBrotli",
712 p.enable_accept_encoding_brotli,
713 );
714 w.open("HeadersConfig");
715 w.element(
716 "HeaderBehavior",
717 if p.headers_config.header_behavior.is_empty() {
718 "none"
719 } else {
720 &p.headers_config.header_behavior
721 },
722 );
723 write_string_list(w, "Headers", "Name", &p.headers_config.headers);
724 w.close("HeadersConfig");
725 w.open("CookiesConfig");
726 w.element(
727 "CookieBehavior",
728 if p.cookies_config.cookie_behavior.is_empty() {
729 "none"
730 } else {
731 &p.cookies_config.cookie_behavior
732 },
733 );
734 write_string_list(w, "Cookies", "Name", &p.cookies_config.cookies);
735 w.close("CookiesConfig");
736 w.open("QueryStringsConfig");
737 w.element(
738 "QueryStringBehavior",
739 if p.query_strings_config.query_string_behavior.is_empty() {
740 "none"
741 } else {
742 &p.query_strings_config.query_string_behavior
743 },
744 );
745 write_string_list(
746 w,
747 "QueryStrings",
748 "Name",
749 &p.query_strings_config.query_strings,
750 );
751 w.close("QueryStringsConfig");
752 w.close("ParametersInCacheKeyAndForwardedToOrigin");
753}
754
755#[must_use]
757pub fn cache_policy_list_xml(items: &[CachePolicy], max_items: i32) -> String {
758 let mut w = XmlWriter::new();
759 w.declaration();
760 w.open_root("CachePolicyList", Some(CLOUDFRONT_XML_NAMESPACE));
761 w.element("Marker", "");
762 w.element_display("MaxItems", max_items);
763 w.bool("IsTruncated", false);
764 w.element_display("Quantity", items.len());
765 if !items.is_empty() {
766 w.open("Items");
767 for p in items {
768 w.open("CachePolicySummary");
769 w.element("Type", if p.managed { "managed" } else { "custom" });
770 w.open("CachePolicy");
771 w.element("Id", &p.id);
772 w.element("LastModifiedTime", &iso8601(&p.last_modified_time));
773 w.open("CachePolicyConfig");
774 write_cache_policy_config_body(&mut w, &p.config);
775 w.close("CachePolicyConfig");
776 w.close("CachePolicy");
777 w.close("CachePolicySummary");
778 }
779 w.close("Items");
780 }
781 w.close("CachePolicyList");
782 w.finish()
783}
784
785#[must_use]
787pub fn origin_request_policy_xml(p: &OriginRequestPolicy) -> String {
788 let mut w = XmlWriter::new();
789 w.declaration();
790 w.open_root("OriginRequestPolicy", Some(CLOUDFRONT_XML_NAMESPACE));
791 w.element("Id", &p.id);
792 w.element("LastModifiedTime", &iso8601(&p.last_modified_time));
793 w.open("OriginRequestPolicyConfig");
794 write_origin_request_policy_body(&mut w, &p.config);
795 w.close("OriginRequestPolicyConfig");
796 w.close("OriginRequestPolicy");
797 w.finish()
798}
799
800#[must_use]
802pub fn origin_request_policy_config_xml(cfg: &OriginRequestPolicyConfig) -> String {
803 let mut w = XmlWriter::new();
804 w.declaration();
805 w.open_root("OriginRequestPolicyConfig", Some(CLOUDFRONT_XML_NAMESPACE));
806 write_origin_request_policy_body(&mut w, cfg);
807 w.close("OriginRequestPolicyConfig");
808 w.finish()
809}
810
811fn write_origin_request_policy_body(w: &mut XmlWriter, cfg: &OriginRequestPolicyConfig) {
812 w.optional_str("Comment", &cfg.comment);
813 w.element("Name", &cfg.name);
814 w.open("HeadersConfig");
815 w.element(
816 "HeaderBehavior",
817 if cfg.headers_config.header_behavior.is_empty() {
818 "none"
819 } else {
820 &cfg.headers_config.header_behavior
821 },
822 );
823 write_string_list(w, "Headers", "Name", &cfg.headers_config.headers);
824 w.close("HeadersConfig");
825 w.open("CookiesConfig");
826 w.element(
827 "CookieBehavior",
828 if cfg.cookies_config.cookie_behavior.is_empty() {
829 "none"
830 } else {
831 &cfg.cookies_config.cookie_behavior
832 },
833 );
834 write_string_list(w, "Cookies", "Name", &cfg.cookies_config.cookies);
835 w.close("CookiesConfig");
836 w.open("QueryStringsConfig");
837 w.element(
838 "QueryStringBehavior",
839 if cfg.query_strings_config.query_string_behavior.is_empty() {
840 "none"
841 } else {
842 &cfg.query_strings_config.query_string_behavior
843 },
844 );
845 write_string_list(
846 w,
847 "QueryStrings",
848 "Name",
849 &cfg.query_strings_config.query_strings,
850 );
851 w.close("QueryStringsConfig");
852}
853
854#[must_use]
856pub fn origin_request_policy_list_xml(items: &[OriginRequestPolicy], max_items: i32) -> String {
857 let mut w = XmlWriter::new();
858 w.declaration();
859 w.open_root("OriginRequestPolicyList", Some(CLOUDFRONT_XML_NAMESPACE));
860 w.element("Marker", "");
861 w.element_display("MaxItems", max_items);
862 w.bool("IsTruncated", false);
863 w.element_display("Quantity", items.len());
864 if !items.is_empty() {
865 w.open("Items");
866 for p in items {
867 w.open("OriginRequestPolicySummary");
868 w.element("Type", if p.managed { "managed" } else { "custom" });
869 w.open("OriginRequestPolicy");
870 w.element("Id", &p.id);
871 w.element("LastModifiedTime", &iso8601(&p.last_modified_time));
872 w.open("OriginRequestPolicyConfig");
873 write_origin_request_policy_body(&mut w, &p.config);
874 w.close("OriginRequestPolicyConfig");
875 w.close("OriginRequestPolicy");
876 w.close("OriginRequestPolicySummary");
877 }
878 w.close("Items");
879 }
880 w.close("OriginRequestPolicyList");
881 w.finish()
882}
883
884#[must_use]
886pub fn response_headers_policy_xml(p: &ResponseHeadersPolicy) -> String {
887 let mut w = XmlWriter::new();
888 w.declaration();
889 w.open_root("ResponseHeadersPolicy", Some(CLOUDFRONT_XML_NAMESPACE));
890 w.element("Id", &p.id);
891 w.element("LastModifiedTime", &iso8601(&p.last_modified_time));
892 w.open("ResponseHeadersPolicyConfig");
893 write_response_headers_policy_body(&mut w, &p.config);
894 w.close("ResponseHeadersPolicyConfig");
895 w.close("ResponseHeadersPolicy");
896 w.finish()
897}
898
899#[must_use]
901pub fn response_headers_policy_config_xml(cfg: &ResponseHeadersPolicyConfig) -> String {
902 let mut w = XmlWriter::new();
903 w.declaration();
904 w.open_root(
905 "ResponseHeadersPolicyConfig",
906 Some(CLOUDFRONT_XML_NAMESPACE),
907 );
908 write_response_headers_policy_body(&mut w, cfg);
909 w.close("ResponseHeadersPolicyConfig");
910 w.finish()
911}
912
913fn write_response_headers_policy_body(w: &mut XmlWriter, cfg: &ResponseHeadersPolicyConfig) {
914 w.optional_str("Comment", &cfg.comment);
915 w.element("Name", &cfg.name);
916 w.open("CorsConfig");
919 if let Some(c) = &cfg.cors_config {
920 w.bool(
921 "AccessControlAllowCredentials",
922 c.access_control_allow_credentials,
923 );
924 write_string_list(
925 w,
926 "AccessControlAllowHeaders",
927 "Header",
928 &c.access_control_allow_headers,
929 );
930 write_string_list(
931 w,
932 "AccessControlAllowMethods",
933 "Method",
934 &c.access_control_allow_methods,
935 );
936 write_string_list(
937 w,
938 "AccessControlAllowOrigins",
939 "Origin",
940 &c.access_control_allow_origins,
941 );
942 write_string_list(
943 w,
944 "AccessControlExposeHeaders",
945 "Header",
946 &c.access_control_expose_headers,
947 );
948 w.element_display("AccessControlMaxAgeSec", c.access_control_max_age_sec);
949 w.bool("OriginOverride", c.origin_override);
950 } else {
951 w.bool("AccessControlAllowCredentials", false);
952 w.element_display("AccessControlMaxAgeSec", 0);
953 w.bool("OriginOverride", false);
954 }
955 w.close("CorsConfig");
956 w.open("SecurityHeadersConfig");
957 w.close("SecurityHeadersConfig");
958 w.open("ServerTimingHeadersConfig");
959 if let Some(s) = &cfg.server_timing_headers_config {
960 w.bool("Enabled", s.enabled);
961 w.element_display("SamplingRate", s.sampling_rate);
962 } else {
963 w.bool("Enabled", false);
964 }
965 w.close("ServerTimingHeadersConfig");
966 write_string_list(
967 w,
968 "RemoveHeadersConfig",
969 "ResponseHeadersPolicyRemoveHeader",
970 &cfg.remove_headers_config,
971 );
972 w.open("CustomHeadersConfig");
973 w.element_display("Quantity", cfg.custom_headers_config.len());
974 if !cfg.custom_headers_config.is_empty() {
975 w.open("Items");
976 for h in &cfg.custom_headers_config {
977 w.open("ResponseHeadersPolicyCustomHeader");
978 w.element("Header", &h.header);
979 w.element("Value", &h.value);
980 w.bool("Override", h.override_upstream);
981 w.close("ResponseHeadersPolicyCustomHeader");
982 }
983 w.close("Items");
984 }
985 w.close("CustomHeadersConfig");
986}
987
988#[must_use]
990pub fn response_headers_policy_list_xml(items: &[ResponseHeadersPolicy], max_items: i32) -> String {
991 let mut w = XmlWriter::new();
992 w.declaration();
993 w.open_root("ResponseHeadersPolicyList", Some(CLOUDFRONT_XML_NAMESPACE));
994 w.element("Marker", "");
995 w.element_display("MaxItems", max_items);
996 w.bool("IsTruncated", false);
997 w.element_display("Quantity", items.len());
998 if !items.is_empty() {
999 w.open("Items");
1000 for p in items {
1001 w.open("ResponseHeadersPolicySummary");
1002 w.element("Type", if p.managed { "managed" } else { "custom" });
1003 w.open("ResponseHeadersPolicy");
1004 w.element("Id", &p.id);
1005 w.element("LastModifiedTime", &iso8601(&p.last_modified_time));
1006 w.open("ResponseHeadersPolicyConfig");
1007 write_response_headers_policy_body(&mut w, &p.config);
1008 w.close("ResponseHeadersPolicyConfig");
1009 w.close("ResponseHeadersPolicy");
1010 w.close("ResponseHeadersPolicySummary");
1011 }
1012 w.close("Items");
1013 }
1014 w.close("ResponseHeadersPolicyList");
1015 w.finish()
1016}
1017
1018#[must_use]
1024pub fn key_group_xml(kg: &KeyGroup) -> String {
1025 let mut w = XmlWriter::new();
1026 w.declaration();
1027 w.open_root("KeyGroup", Some(CLOUDFRONT_XML_NAMESPACE));
1028 w.element("Id", &kg.id);
1029 w.element("LastModifiedTime", &iso8601(&kg.last_modified_time));
1030 w.open("KeyGroupConfig");
1031 w.element("Name", &kg.config.name);
1032 write_string_list(&mut w, "Items", "PublicKey", &kg.config.items);
1033 w.element("Comment", &kg.config.comment);
1034 w.close("KeyGroupConfig");
1035 w.close("KeyGroup");
1036 w.finish()
1037}
1038
1039#[must_use]
1041pub fn key_group_list_xml(items: &[KeyGroup], max_items: i32) -> String {
1042 let mut w = XmlWriter::new();
1043 w.declaration();
1044 w.open_root("KeyGroupList", Some(CLOUDFRONT_XML_NAMESPACE));
1045 w.element_display("MaxItems", max_items);
1046 w.element_display("Quantity", items.len());
1047 if !items.is_empty() {
1048 w.open("Items");
1049 for kg in items {
1050 w.open("KeyGroupSummary");
1051 w.open("KeyGroup");
1052 w.element("Id", &kg.id);
1053 w.element("LastModifiedTime", &iso8601(&kg.last_modified_time));
1054 w.open("KeyGroupConfig");
1055 w.element("Name", &kg.config.name);
1056 write_string_list(&mut w, "Items", "PublicKey", &kg.config.items);
1057 w.element("Comment", &kg.config.comment);
1058 w.close("KeyGroupConfig");
1059 w.close("KeyGroup");
1060 w.close("KeyGroupSummary");
1061 }
1062 w.close("Items");
1063 }
1064 w.close("KeyGroupList");
1065 w.finish()
1066}
1067
1068#[must_use]
1070pub fn public_key_xml(k: &PublicKey) -> String {
1071 let mut w = XmlWriter::new();
1072 w.declaration();
1073 w.open_root("PublicKey", Some(CLOUDFRONT_XML_NAMESPACE));
1074 w.element("Id", &k.id);
1075 w.element("CreatedTime", &iso8601(&k.created_time));
1076 w.open("PublicKeyConfig");
1077 w.element("CallerReference", &k.config.caller_reference);
1078 w.element("Name", &k.config.name);
1079 w.element("EncodedKey", &k.config.encoded_key);
1080 w.element("Comment", &k.config.comment);
1081 w.close("PublicKeyConfig");
1082 w.close("PublicKey");
1083 w.finish()
1084}
1085
1086#[must_use]
1088pub fn public_key_list_xml(items: &[PublicKey], max_items: i32) -> String {
1089 let mut w = XmlWriter::new();
1090 w.declaration();
1091 w.open_root("PublicKeyList", Some(CLOUDFRONT_XML_NAMESPACE));
1092 w.element_display("MaxItems", max_items);
1093 w.element_display("Quantity", items.len());
1094 if !items.is_empty() {
1095 w.open("Items");
1096 for k in items {
1097 w.open("PublicKeySummary");
1098 w.element("Id", &k.id);
1099 w.element("Name", &k.config.name);
1100 w.element("CreatedTime", &iso8601(&k.created_time));
1101 w.element("EncodedKey", &k.config.encoded_key);
1102 w.element("Comment", &k.config.comment);
1103 w.close("PublicKeySummary");
1104 }
1105 w.close("Items");
1106 }
1107 w.close("PublicKeyList");
1108 w.finish()
1109}
1110
1111#[must_use]
1113pub fn function_xml(f: &CloudFrontFunction) -> String {
1114 let mut w = XmlWriter::new();
1115 w.declaration();
1116 w.open_root("FunctionSummary", Some(CLOUDFRONT_XML_NAMESPACE));
1117 w.element("Name", &f.name);
1118 w.element("Status", &f.status);
1119 write_function_metadata(&mut w, f);
1120 write_function_config(&mut w, &f.config);
1121 w.close("FunctionSummary");
1122 w.finish()
1123}
1124
1125fn write_function_metadata(w: &mut XmlWriter, f: &CloudFrontFunction) {
1126 w.open("FunctionMetadata");
1127 w.element("FunctionARN", &f.metadata.function_arn);
1128 w.element("Stage", &f.metadata.stage);
1129 w.element("CreatedTime", &iso8601(&f.metadata.created_time));
1130 w.element("LastModifiedTime", &iso8601(&f.metadata.last_modified_time));
1131 w.close("FunctionMetadata");
1132}
1133
1134fn write_function_config(w: &mut XmlWriter, cfg: &FunctionConfig) {
1135 w.open("FunctionConfig");
1136 w.element("Comment", &cfg.comment);
1137 w.element("Runtime", &cfg.runtime);
1138 w.close("FunctionConfig");
1139}
1140
1141#[must_use]
1143pub fn function_list_xml(items: &[CloudFrontFunction], max_items: i32) -> String {
1144 let mut w = XmlWriter::new();
1145 w.declaration();
1146 w.open_root("FunctionList", Some(CLOUDFRONT_XML_NAMESPACE));
1147 w.element_display("MaxItems", max_items);
1148 w.element_display("Quantity", items.len());
1149 if !items.is_empty() {
1150 w.open("Items");
1151 for f in items {
1152 w.open("FunctionSummary");
1153 w.element("Name", &f.name);
1154 w.element("Status", &f.status);
1155 write_function_metadata(&mut w, f);
1156 write_function_config(&mut w, &f.config);
1157 w.close("FunctionSummary");
1158 }
1159 w.close("Items");
1160 }
1161 w.close("FunctionList");
1162 w.finish()
1163}
1164
1165#[must_use]
1171pub fn fle_xml(f: &FieldLevelEncryption) -> String {
1172 let mut w = XmlWriter::new();
1173 w.declaration();
1174 w.open_root("FieldLevelEncryption", Some(CLOUDFRONT_XML_NAMESPACE));
1175 w.element("Id", &f.id);
1176 w.element("LastModifiedTime", &iso8601(&f.last_modified_time));
1177 w.open("FieldLevelEncryptionConfig");
1178 w.element("CallerReference", &f.config.caller_reference);
1179 w.element("Comment", &f.config.comment);
1180 w.close("FieldLevelEncryptionConfig");
1181 w.close("FieldLevelEncryption");
1182 w.finish()
1183}
1184
1185#[must_use]
1187pub fn fle_profile_xml(f: &FieldLevelEncryptionProfile) -> String {
1188 let mut w = XmlWriter::new();
1189 w.declaration();
1190 w.open_root(
1191 "FieldLevelEncryptionProfile",
1192 Some(CLOUDFRONT_XML_NAMESPACE),
1193 );
1194 w.element("Id", &f.id);
1195 w.element("LastModifiedTime", &iso8601(&f.last_modified_time));
1196 w.open("FieldLevelEncryptionProfileConfig");
1197 w.element("Name", &f.config.name);
1198 w.element("CallerReference", &f.config.caller_reference);
1199 w.element("Comment", &f.config.comment);
1200 w.close("FieldLevelEncryptionProfileConfig");
1201 w.close("FieldLevelEncryptionProfile");
1202 w.finish()
1203}
1204
1205#[must_use]
1207pub fn kvs_xml(k: &KeyValueStore) -> String {
1208 let mut w = XmlWriter::new();
1209 w.declaration();
1210 w.open_root("KeyValueStore", Some(CLOUDFRONT_XML_NAMESPACE));
1211 w.element("Name", &k.name);
1212 w.element("Id", &k.id);
1213 w.element("Comment", &k.comment);
1214 w.element("ARN", &k.arn);
1215 w.element("Status", &k.status);
1216 w.element("LastModifiedTime", &iso8601(&k.last_modified_time));
1217 w.close("KeyValueStore");
1218 w.finish()
1219}
1220
1221#[must_use]
1223pub fn realtime_log_config_xml(r: &RealtimeLogConfig) -> String {
1224 let mut w = XmlWriter::new();
1225 w.declaration();
1226 w.open_root("RealtimeLogConfig", Some(CLOUDFRONT_XML_NAMESPACE));
1227 w.element("ARN", &r.arn);
1228 w.element("Name", &r.name);
1229 w.element_display("SamplingRate", r.sampling_rate);
1230 write_string_list(&mut w, "Fields", "Field", &r.fields);
1231 w.open("EndPoints");
1232 for ep in &r.end_points {
1233 w.open("EndPoint");
1234 w.element("StreamType", &ep.stream_type);
1235 w.open("KinesisStreamConfig");
1236 w.element("RoleARN", &ep.kinesis_stream_config.role_arn);
1237 w.element("StreamARN", &ep.kinesis_stream_config.stream_arn);
1238 w.close("KinesisStreamConfig");
1239 w.close("EndPoint");
1240 }
1241 w.close("EndPoints");
1242 w.close("RealtimeLogConfig");
1243 w.finish()
1244}
1245
1246#[must_use]
1252pub fn tags_xml(tags: &TagSet) -> String {
1253 let mut w = XmlWriter::new();
1254 w.declaration();
1255 w.open_root("Tags", Some(CLOUDFRONT_XML_NAMESPACE));
1256 w.open("Items");
1257 for t in tags {
1258 w.open("Tag");
1259 w.element("Key", &t.key);
1260 w.element("Value", &t.value);
1261 w.close("Tag");
1262 }
1263 w.close("Items");
1264 w.close("Tags");
1265 w.finish()
1266}
1267
1268#[must_use]
1274pub fn error_xml(code: &str, message: &str, request_id: &str) -> String {
1275 let mut w = XmlWriter::new();
1276 w.declaration();
1277 w.open_root("ErrorResponse", Some(CLOUDFRONT_XML_NAMESPACE));
1278 w.open("Error");
1279 w.element("Type", "Sender");
1280 w.element("Code", code);
1281 w.element("Message", message);
1282 w.close("Error");
1283 w.element("RequestId", request_id);
1284 w.close("ErrorResponse");
1285 w.finish()
1286}
1287
1288impl XmlWriter {
1293 pub fn buf_mut_push_namespace_open(&mut self, name: &str) {
1295 self.open_root(name, Some(CLOUDFRONT_XML_NAMESPACE));
1296 }
1297}
1298
1299fn write_distribution_config_body(w: &mut XmlWriter, cfg: &DistributionConfig) {
1300 w.element("CallerReference", &cfg.caller_reference);
1301 write_string_list(w, "Aliases", "CNAME", &cfg.aliases);
1302 w.element("DefaultRootObject", &cfg.default_root_object);
1303 write_origins(w, &cfg.origins);
1304 write_origin_groups(w, &cfg.origin_groups);
1305 write_default_cache_behavior(w, &cfg.default_cache_behavior);
1306 write_cache_behaviors(w, &cfg.cache_behaviors);
1307 write_custom_error_responses(w, &cfg.custom_error_responses);
1308 w.element("Comment", &cfg.comment);
1309 write_logging(w, cfg);
1310 w.optional_str("PriceClass", &cfg.price_class);
1311 w.bool("Enabled", cfg.enabled);
1312 write_viewer_certificate(w, cfg);
1313 write_restrictions(w, cfg);
1314 w.optional_str("WebACLId", &cfg.web_acl_id);
1315 w.optional_str("HttpVersion", &cfg.http_version);
1316 w.bool("IsIPV6Enabled", cfg.is_ipv6_enabled);
1317 w.bool("Staging", cfg.staging);
1318}