1use reqwest::StatusCode;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5pub mod builder {
6
7 use super::*;
8
9 #[derive(Debug, Clone, Default)]
10 pub struct MirrorHeadersBuilder<'a> {
11 pass_all: bool,
12 pass: Vec<&'a str>,
13 remove: Vec<&'a str>,
14 set: Vec<(&'a str, &'a str)>,
15 }
16
17 impl<'a> MirrorHeadersBuilder<'a> {
18 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub fn with_pass_all(mut self, value: bool) -> Self {
23 self.pass_all = value;
24 self
25 }
26
27 pub fn with_pass(mut self, value: Vec<&'a str>) -> Self {
28 self.pass = value;
29 self
30 }
31
32 pub fn with_remove(mut self, value: Vec<&'a str>) -> Self {
33 self.remove = value;
34 self
35 }
36
37 pub fn with_set(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
38 self.set = value;
39 self
40 }
41
42 pub fn build(&self) -> MirrorHeaders {
43 MirrorHeaders {
44 pass_all: Some(self.pass_all),
45 pass: if self.pass.is_empty() {
46 None
47 } else {
48 Some(self.pass.iter().map(|value| value.to_string()).collect())
49 },
50 remove: if self.remove.is_empty() {
51 None
52 } else {
53 Some(self.remove.iter().map(|value| value.to_string()).collect())
54 },
55 set: if self.set.is_empty() {
56 None
57 } else {
58 Some({
59 self.set
60 .iter()
61 .map(|item| Set {
62 key: item.0.to_string(),
63 value: item.1.to_string(),
64 })
65 .collect()
66 })
67 },
68 }
69 }
70 }
71
72 #[derive(Debug, Default, Clone)]
73 pub struct RedirectBuilder<'a> {
74 redirect_type: RedirectType,
75 protocol: Option<&'a str>,
76 pass_query_string: Option<&'a str>,
77 replace_key_with: Option<&'a str>,
78 mirror_url: Option<&'a str>,
79 mirror_pass_query_string: Option<bool>,
80 mirror_follow_redirect: Option<bool>,
81 mirror_check_md5: Option<bool>,
82 mirror_headers: Option<MirrorHeaders>,
83 enable_replace_prefix: Option<bool>,
84 mirror_replace_prefix: Option<bool>,
85 http_replace_code: Option<u16>,
86 replace_key_prefix_with: Option<&'a str>,
87 host_name: Option<&'a str>,
88 }
89
90 impl<'a> RedirectBuilder<'a> {
91 pub fn new() -> Self {
92 Self::default()
93 }
94
95 pub fn with_redirect_type(mut self, value: RedirectType) -> Self {
96 self.redirect_type = value;
97 self
98 }
99
100 pub fn with_protocol(mut self, value: &'a str) -> Self {
101 self.protocol = Some(value);
102 self
103 }
104
105 pub fn pass_query_string(mut self, value: &'a str) -> Self {
106 self.pass_query_string = Some(value);
107 self
108 }
109
110 pub fn with_replace_key_with(mut self, value: &'a str) -> Self {
111 self.replace_key_prefix_with = Some(value);
112 self
113 }
114
115 pub fn with_mirror_url(mut self, value: &'a str) -> Self {
116 self.mirror_url = Some(value);
117 self
118 }
119
120 pub fn with_mirror_pass_query_string(mut self, value: bool) -> Self {
121 self.mirror_pass_query_string = Some(value);
122 self
123 }
124
125 pub fn with_mirror_follow_redirect(mut self, value: bool) -> Self {
126 self.mirror_follow_redirect = Some(value);
127 self
128 }
129 pub fn with_mirror_check_md5(mut self, value: bool) -> Self {
130 self.mirror_check_md5 = Some(value);
131 self
132 }
133
134 pub fn with_mirror_headers(mut self, value: MirrorHeaders) -> Self {
135 self.mirror_headers = Some(value);
136 self
137 }
138
139 pub fn with_mirror_replace_prefix(mut self, value: bool) -> Self {
140 self.mirror_replace_prefix = Some(value);
141 self
142 }
143
144 pub fn with_http_replace_code(mut self, value: u16) -> Self {
145 self.http_replace_code = Some(value);
146 self
147 }
148
149 pub fn with_replace_key_prefix_with(mut self, value: &'a str) -> Self {
150 self.replace_key_prefix_with = Some(value);
151 self
152 }
153
154 pub fn with_host_name(mut self, value: &'a str) -> Self {
155 self.host_name = Some(value);
156 self
157 }
158
159 pub fn build(&self) -> Redirect {
160 Redirect {
161 redirect_type: self.redirect_type.clone(),
162 protocol: self.protocol.map(|e| e.to_string()),
163 pass_query_string: self.pass_query_string.map(|e| e.to_string()),
164 replace_key_with: self.replace_key_with.map(|e| e.to_string()),
165 mirror_url: self.mirror_url.map(|e| e.to_string()),
166 mirror_pass_query_string: self.mirror_pass_query_string,
167 mirror_follow_redirect: self.mirror_follow_redirect,
168 mirror_check_md5: self.mirror_check_md5,
169 mirror_headers: self.mirror_headers.clone(),
170 enable_replace_prefix: self.enable_replace_prefix,
171 http_redirect_code: self.http_replace_code,
172 replace_key_prefix_with: self.replace_key_prefix_with.map(|e| e.to_string()),
173 host_name: self.host_name.map(|e| e.to_string()),
174 }
175 }
176 }
177
178 #[derive(Debug, Default)]
179 pub struct ConditionBuilder<'a> {
180 pub key_prefix_equals: Option<&'a str>,
181 pub http_error_code_returned_equals: Option<u16>,
182 pub key_suffix_equals: Option<&'a str>,
183 pub include_header_key: Option<&'a str>,
184 pub include_header_equals: Option<&'a str>,
185 }
186
187 impl<'a> ConditionBuilder<'a> {
188 pub fn new() -> Self {
189 Self::default()
190 }
191
192 pub fn with_key_prefix_equals(mut self, value: &'a str) -> Self {
193 self.key_prefix_equals = Some(value);
194 self
195 }
196
197 pub fn with_http_error_code_returned_equals(mut self, value: u16) -> Self {
198 self.http_error_code_returned_equals = Some(value);
199 self
200 }
201
202 pub fn with_key_suffix_equals(mut self, value: &'a str) -> Self {
203 self.key_suffix_equals = Some(value);
204 self
205 }
206
207 pub fn with_include_header_key(mut self, value: &'a str) -> Self {
208 self.include_header_key = Some(value);
209 self
210 }
211
212 pub fn with_include_header_equals(mut self, value: &'a str) -> Self {
213 self.include_header_equals = Some(value);
214 self
215 }
216
217 pub fn build(&self) -> Condition {
218 Condition {
219 include_header: if let Some(include_header_key) = self.include_header_key {
220 Some(IncludeHeader {
221 key: include_header_key.to_string(),
222 equals: self.include_header_equals.map(|e| e.to_string()),
223 })
224 } else {
225 None
226 },
227 key_prefix_equals: self.key_prefix_equals.map(|e| e.to_string()),
228 http_error_code_returned_equals: self.http_error_code_returned_equals,
229 key_suffix_equals: self.key_suffix_equals.map(|e| e.to_string()),
230 }
231 }
232 }
233
234 #[derive(Debug, Default)]
235 pub struct IndexDocumentBuilder<'a> {
236 suffix: &'a str,
237 support_sub_dir: bool,
238 r#type: u16,
239 }
240
241 impl<'a> IndexDocumentBuilder<'a> {
242 pub fn new() -> Self {
243 Self::default()
244 }
245
246 pub fn with_suffix(mut self, value: &'a str) -> Self {
247 self.suffix = value;
248 self
249 }
250
251 pub fn with_support_sub_dir(mut self, value: bool) -> Self {
252 self.support_sub_dir = value;
253 self
254 }
255
256 pub fn with_type(mut self, value: u16) -> Self {
257 self.r#type = value;
258 self
259 }
260
261 pub fn build(&self) -> IndexDocument {
262 IndexDocument {
263 suffix: self.suffix.to_string(),
264 support_sub_dir: Some(self.support_sub_dir),
265 r#type: Some(self.r#type),
266 }
267 }
268 }
269
270 #[derive(Debug, Default)]
271 pub struct ErrorDocumentBuilder<'a> {
272 key: &'a str,
273 http_status: StatusCode,
274 }
275
276 impl<'a> ErrorDocumentBuilder<'a> {
277 pub fn new() -> Self {
278 Self::default()
279 }
280
281 pub fn with_key(mut self, value: &'a str) -> Self {
282 self.key = value;
283 self
284 }
285
286 pub fn with_http_status(mut self, value: StatusCode) -> Self {
287 self.http_status = value;
288 self
289 }
290
291 pub fn build(&self) -> ErrorDocument {
292 ErrorDocument {
293 key: self.key.to_string(),
294 http_status: Some(self.http_status.as_u16()),
295 }
296 }
297 }
298
299 #[derive(Debug, Default, Clone)]
300 pub struct RoutingRuleBuilder {
301 rule: RoutingRule,
302 }
303
304 impl RoutingRuleBuilder {
305 pub fn new() -> Self {
306 Self::default()
307 }
308
309 pub fn with_rule_number(mut self, value: u32) -> Self {
310 self.rule.rule_number = value;
311 self
312 }
313
314 pub fn with_condition(mut self, value: Condition) -> Self {
315 self.rule.condition = value;
316 self
317 }
318 pub fn with_redirect(mut self, value: Redirect) -> Self {
319 self.rule.redirect = value;
320 self
321 }
322
323 pub fn build(&self) -> RoutingRule {
324 self.rule.clone()
325 }
326 }
327
328 #[derive(Debug, Default, Clone)]
329 pub struct RoutingRulesBuilder {
330 rules: Vec<RoutingRule>,
331 }
332
333 impl RoutingRulesBuilder {
334 pub fn new() -> Self {
335 Self::default()
336 }
337
338 pub fn with_rule(mut self, value: RoutingRule) -> Self {
339 self.rules.push(value);
340 self
341 }
342
343 pub fn build(&self) -> RoutingRules {
344 RoutingRules {
345 routing_rule: if self.rules.is_empty() {
346 None
347 } else {
348 Some(self.rules.clone())
349 },
350 }
351 }
352 }
353
354 #[derive(Debug, Default)]
355 pub struct WebsiteConfigurationBuilder {
356 pub index_document: Option<IndexDocument>,
357 pub error_document: Option<ErrorDocument>,
358 pub routing_rules: Option<RoutingRules>,
359 }
360
361 impl WebsiteConfigurationBuilder {
362 pub fn new() -> Self {
363 Self::default()
364 }
365
366 pub fn with_index_document(mut self, value: IndexDocument) -> Self {
367 self.index_document = Some(value);
368 self
369 }
370 pub fn with_error_document(mut self, value: ErrorDocument) -> Self {
371 self.error_document = Some(value);
372 self
373 }
374
375 pub fn with_routing_rules(mut self, value: RoutingRules) -> Self {
376 self.routing_rules = Some(value);
377 self
378 }
379
380 pub fn build(&self) -> WebsiteConfiguration {
381 WebsiteConfiguration {
382 index_document: self.index_document.clone(),
383 error_document: self.error_document.clone(),
384 routing_rules: self.routing_rules.clone(),
385 }
386 }
387 }
388}
389
390#[derive(Debug, Clone, Serialize, Deserialize, Default)]
391pub enum RedirectType {
392 #[default]
393 Mirror,
395 External,
397 AliCDN,
401}
402
403impl fmt::Display for RedirectType {
404 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
405 write!(
406 f,
407 "{}",
408 match self {
409 Self::Mirror => "Mirror",
410 Self::External => "External",
411 Self::AliCDN => "AliCDN",
412 }
413 )
414 }
415}
416
417#[derive(Debug, Default, Clone, Serialize, Deserialize)]
418pub struct Set {
419 #[serde(rename = "Key")]
420 pub key: String,
421 #[serde(rename = "Value")]
422 pub value: String,
423}
424
425#[derive(Debug, Default, Clone, Serialize, Deserialize)]
426pub struct MirrorHeaders {
427 #[serde(rename = "PassAll", skip_serializing_if = "Option::is_none")]
428 pub pass_all: Option<bool>,
429 #[serde(rename = "Pass", skip_serializing_if = "Option::is_none")]
430 pub pass: Option<Vec<String>>,
431 #[serde(rename = "Remove", skip_serializing_if = "Option::is_none")]
432 pub remove: Option<Vec<String>>,
433 #[serde(rename = "Set", skip_serializing_if = "Option::is_none")]
434 pub set: Option<Vec<Set>>,
435}
436
437#[derive(Debug, Default, Clone, Serialize, Deserialize)]
438pub struct Redirect {
439 #[serde(rename = "RedirectType")]
440 pub redirect_type: RedirectType,
441 #[serde(rename = "Protocol", skip_serializing_if = "Option::is_none")]
442 pub protocol: Option<String>,
443 #[serde(rename = "PassQueryString", skip_serializing_if = "Option::is_none")]
444 pub pass_query_string: Option<String>,
445 #[serde(rename = "ReplaceKeyWith", skip_serializing_if = "Option::is_none")]
446 pub replace_key_with: Option<String>,
447 #[serde(rename = "MirrorURL", skip_serializing_if = "Option::is_none")]
448 pub mirror_url: Option<String>,
449 #[serde(
450 rename = "MirrorPassQueryString",
451 skip_serializing_if = "Option::is_none"
452 )]
453 pub mirror_pass_query_string: Option<bool>,
454 #[serde(
455 rename = "MirrorFollowRedirect",
456 skip_serializing_if = "Option::is_none"
457 )]
458 pub mirror_follow_redirect: Option<bool>,
459 #[serde(rename = "MirrorCheckMd5", skip_serializing_if = "Option::is_none")]
460 pub mirror_check_md5: Option<bool>,
461 #[serde(rename = "MirrorHeaders", skip_serializing_if = "Option::is_none")]
462 pub mirror_headers: Option<MirrorHeaders>,
463 #[serde(
464 rename = "EnableReplacePrefix",
465 skip_serializing_if = "Option::is_none"
466 )]
467 pub enable_replace_prefix: Option<bool>,
468 #[serde(rename = "HttpRedirectCode", skip_serializing_if = "Option::is_none")]
469 pub http_redirect_code: Option<u16>,
470 #[serde(
471 rename = "ReplaceKeyPrefixWith",
472 skip_serializing_if = "Option::is_none"
473 )]
474 pub replace_key_prefix_with: Option<String>,
475 #[serde(rename = "HostName", skip_serializing_if = "Option::is_none")]
476 pub host_name: Option<String>,
477}
478
479#[derive(Debug, Default, Clone, Serialize, Deserialize)]
480pub struct IncludeHeader {
481 #[serde(rename = "Key")]
482 pub key: String,
483 #[serde(rename = "Equals", skip_serializing_if = "Option::is_none")]
484 pub equals: Option<String>,
485}
486
487#[derive(Debug, Default, Clone, Serialize, Deserialize)]
488pub struct Condition {
489 #[serde(rename = "KeyPrefixEquals", skip_serializing_if = "Option::is_none")]
490 pub key_prefix_equals: Option<String>,
491 #[serde(
492 rename = "HttpErrorCodeReturnedEquals",
493 skip_serializing_if = "Option::is_none"
494 )]
495 pub http_error_code_returned_equals: Option<u16>,
496 #[serde(rename = "IncludeHeader", skip_serializing_if = "Option::is_none")]
497 pub include_header: Option<IncludeHeader>,
498 #[serde(rename = "KeySuffixEquals", skip_serializing_if = "Option::is_none")]
499 pub key_suffix_equals: Option<String>,
500}
501
502#[derive(Debug, Default, Clone, Serialize, Deserialize)]
503pub struct RoutingRule {
504 #[serde(rename = "RuleNumber")]
505 pub rule_number: u32,
506 #[serde(rename = "Condition")]
507 pub condition: Condition,
508 #[serde(rename = "Redirect")]
509 pub redirect: Redirect,
510}
511
512#[derive(Debug, Default, Clone, Serialize, Deserialize)]
513pub struct RoutingRules {
514 #[serde(rename = "RoutingRule", skip_serializing_if = "Option::is_none")]
515 pub routing_rule: Option<Vec<RoutingRule>>,
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
519pub struct IndexDocument {
521 #[serde(rename = "Suffix")]
522 pub suffix: String,
524 #[serde(rename = "SupportSubDir", skip_serializing_if = "Option::is_none")]
525 pub support_sub_dir: Option<bool>,
527 #[serde(rename = "Type", skip_serializing_if = "Option::is_none")]
528 pub r#type: Option<u16>,
530}
531
532impl Default for IndexDocument {
533 fn default() -> Self {
534 Self {
535 suffix: "index.html".to_string(),
536 support_sub_dir: Some(true),
537 r#type: Some(0),
538 }
539 }
540}
541
542#[derive(Debug, Clone, Serialize, Deserialize)]
543pub struct ErrorDocument {
544 #[serde(rename = "Key")]
545 pub key: String,
546 #[serde(rename = "HttpStatus", skip_serializing_if = "Option::is_none")]
547 pub http_status: Option<u16>,
548}
549
550impl Default for ErrorDocument {
551 fn default() -> Self {
552 Self {
553 key: "error.html".to_string(),
554 http_status: Some(StatusCode::NOT_FOUND.as_u16()),
555 }
556 }
557}
558
559#[derive(Debug, Default, Clone, Serialize, Deserialize)]
560pub struct WebsiteConfiguration {
561 #[serde(rename = "IndexDocument", skip_serializing_if = "Option::is_none")]
563 pub index_document: Option<IndexDocument>,
564 #[serde(rename = "ErrorDocument", skip_serializing_if = "Option::is_none")]
565 pub error_document: Option<ErrorDocument>,
566 #[serde(rename = "RoutingRules", skip_serializing_if = "Option::is_none")]
567 pub routing_rules: Option<RoutingRules>,
568}
569
570#[cfg(test)]
571pub mod tests {
572 use reqwest::StatusCode;
573
574 use super::{
575 builder::{
576 ConditionBuilder, ErrorDocumentBuilder, IndexDocumentBuilder, MirrorHeadersBuilder,
577 RedirectBuilder, RoutingRulesBuilder, WebsiteConfigurationBuilder,
578 },
579 RedirectType,
580 };
581 use crate::oss::entities::website::{RoutingRule, Set, WebsiteConfiguration};
582
583 #[test]
584 fn website_configuration_parse_1() {
585 let xml_content = r#"<WebsiteConfiguration>
586<IndexDocument>
587 <Suffix>index.html</Suffix>
588 <SupportSubDir>true</SupportSubDir>
589 <Type>0</Type>
590</IndexDocument>
591<ErrorDocument>
592 <Key>error.html</Key>
593 <HttpStatus>404</HttpStatus>
594</ErrorDocument>
595<RoutingRules>
596 <RoutingRule>
597 <RuleNumber>1</RuleNumber>
598 <Condition>
599 <KeyPrefixEquals>abc/</KeyPrefixEquals>
600 <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
601 </Condition>
602 <Redirect>
603 <RedirectType>Mirror</RedirectType>
604 <PassQueryString>true</PassQueryString>
605 <MirrorURL>http://example.com/</MirrorURL>
606 <MirrorPassQueryString>true</MirrorPassQueryString>
607 <MirrorFollowRedirect>true</MirrorFollowRedirect>
608 <MirrorCheckMd5>false</MirrorCheckMd5>
609 <MirrorHeaders>
610 <PassAll>true</PassAll>
611 <Pass>myheader-key1</Pass>
612 <Pass>myheader-key2</Pass>
613 <Remove>myheader-key3</Remove>
614 <Remove>myheader-key4</Remove>
615 <Set>
616 <Key>myheader-key5</Key>
617 <Value>myheader-value5</Value>
618 </Set>
619 </MirrorHeaders>
620 </Redirect>
621 </RoutingRule>
622 <RoutingRule>
623 <RuleNumber>2</RuleNumber>
624 <Condition>
625 <KeyPrefixEquals>abc/</KeyPrefixEquals>
626 <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
627 <IncludeHeader>
628 <Key>host</Key>
629 <Equals>test.oss-cn-beijing-internal.aliyuncs.com</Equals>
630 </IncludeHeader>
631 </Condition>
632 <Redirect>
633 <RedirectType>AliCDN</RedirectType>
634 <Protocol>http</Protocol>
635 <HostName>example.com</HostName>
636 <PassQueryString>false</PassQueryString>
637 <ReplaceKeyWith>prefix/${key}.suffix</ReplaceKeyWith>
638 <HttpRedirectCode>301</HttpRedirectCode>
639 </Redirect>
640 </RoutingRule>
641 <RoutingRule>
642 <Condition>
643 <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
644 </Condition>
645 <RuleNumber>3</RuleNumber>
646 <Redirect>
647 <ReplaceKeyWith>prefix/${key}</ReplaceKeyWith>
648 <HttpRedirectCode>302</HttpRedirectCode>
649 <EnableReplacePrefix>false</EnableReplacePrefix>
650 <PassQueryString>false</PassQueryString>
651 <Protocol>http</Protocol>
652 <HostName>example.com</HostName>
653 <RedirectType>External</RedirectType>
654 </Redirect>
655 </RoutingRule>
656</RoutingRules>
657</WebsiteConfiguration>
658"#;
659
660 let object: WebsiteConfiguration = quick_xml::de::from_str(xml_content).unwrap();
661 let left = "index.html";
662 let right = object.index_document.unwrap().suffix;
663 assert_eq!(left, right)
664 }
665
666 #[test]
667 fn website_configuration_parse_2() {
668 let xml_content = r#"<?xml version="1.0" encoding="UTF-8"?>
669<WebsiteConfiguration>
670 <IndexDocument>
671 <Suffix>index.html</Suffix>
672 </IndexDocument>
673 <ErrorDocument>
674 <Key>error.html</Key>
675 <HttpStatus>404</HttpStatus>
676 </ErrorDocument>
677 <RoutingRules>
678 <RoutingRule>
679 <RuleNumber>1</RuleNumber>
680 <Condition>
681 <KeyPrefixEquals>abc/</KeyPrefixEquals>
682 <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
683 </Condition>
684 <Redirect>
685 <RedirectType>Mirror</RedirectType>
686 <PassQueryString>true</PassQueryString>
687 <MirrorURL>http://example.com/</MirrorURL>
688 <MirrorPassQueryString>true</MirrorPassQueryString>
689 <MirrorFollowRedirect>true</MirrorFollowRedirect>
690 <MirrorCheckMd5>false</MirrorCheckMd5>
691 <MirrorHeaders>
692 <PassAll>true</PassAll>
693 <Pass>myheader-key1</Pass>
694 <Pass>myheader-key2</Pass>
695 <Remove>myheader-key3</Remove>
696 <Remove>myheader-key4</Remove>
697 <Set>
698 <Key>myheader-key5</Key>
699 <Value>myheader-value5</Value>
700 </Set>
701 </MirrorHeaders>
702 </Redirect>
703 </RoutingRule>
704 <RoutingRule>
705 <RuleNumber>2</RuleNumber>
706 <Condition>
707 <IncludeHeader>
708 <Key>host</Key>
709 <Equals>test.oss-cn-beijing-internal.aliyuncs.com</Equals>
710 </IncludeHeader>
711 <KeyPrefixEquals>abc/</KeyPrefixEquals>
712 <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
713 </Condition>
714 <Redirect>
715 <RedirectType>AliCDN</RedirectType>
716 <Protocol>http</Protocol>
717 <HostName>example.com</HostName>
718 <PassQueryString>false</PassQueryString>
719 <ReplaceKeyWith>prefix/${key}.suffix</ReplaceKeyWith>
720 <HttpRedirectCode>301</HttpRedirectCode>
721 </Redirect>
722 </RoutingRule>
723 </RoutingRules>
724</WebsiteConfiguration>"#;
725
726 let object: WebsiteConfiguration = quick_xml::de::from_str(xml_content).unwrap();
727 let left = "index.html";
728 let right = object.index_document.unwrap().suffix;
729 assert_eq!(left, right)
730 }
731
732 #[test]
733 fn mirror_headers_builder() {
734 let obj = MirrorHeadersBuilder::new()
735 .with_pass(["pass1", "pass2"].to_vec())
736 .with_remove(["remove1", "remove2"].to_vec())
737 .with_pass_all(true)
738 .with_set([("lable", "value"), ("label1", "value1")].to_vec())
739 .build();
740 let left = Set {
741 key: "label1".to_string(),
742 value: "value1".to_string(),
743 };
744 let right = &obj.set.unwrap()[1];
745 assert_eq!(left.key, right.key);
746 }
747
748 #[test]
749 fn redirect_builder() {
750 let redirect = RedirectBuilder::new()
751 .with_host_name("xuetube.com")
752 .with_http_replace_code(302)
753 .with_mirror_check_md5(true)
754 .with_mirror_follow_redirect(false)
755 .with_mirror_headers(
756 MirrorHeadersBuilder::new()
757 .with_pass(["pass1", "pass2"].to_vec())
758 .with_remove(["remove1", "remove2"].to_vec())
759 .with_pass_all(true)
760 .with_set([("name", "sjy"), ("age", "18")].to_vec())
761 .build(),
762 )
763 .with_mirror_pass_query_string(false)
764 .with_mirror_replace_prefix(false)
765 .with_mirror_url("http://example.com")
766 .with_protocol("https")
767 .with_redirect_type(RedirectType::AliCDN)
768 .with_replace_key_with("test")
769 .build();
770 let left = "pass1";
771 let right = &redirect.mirror_headers.unwrap().pass.unwrap()[0];
772 assert_eq!(left, right);
773 }
774
775 #[test]
776 fn condition_builder() {
777 let condition = ConditionBuilder::new()
778 .with_include_header_key("key")
779 .with_include_header_equals("test")
780 .with_http_error_code_returned_equals(203)
781 .with_key_prefix_equals("prefix")
782 .with_key_suffix_equals("suffix")
783 .build();
784 let left = "key";
785 let right = condition.include_header.unwrap().key;
786 assert_eq!(left, right);
787 }
788
789 #[test]
790 fn web_config_builder() {
791 let config = WebsiteConfigurationBuilder::new()
792 .with_index_document(
793 IndexDocumentBuilder::new()
794 .with_suffix("test")
795 .with_support_sub_dir(true)
796 .with_type(200)
797 .build(),
798 )
799 .with_error_document(
800 ErrorDocumentBuilder::new()
801 .with_http_status(StatusCode::NOT_FOUND)
802 .with_key("abcd")
803 .build(),
804 )
805 .with_routing_rules(
806 RoutingRulesBuilder::new()
807 .with_rule(RoutingRule {
808 rule_number: 100,
809 condition: ConditionBuilder::new().build(),
810 redirect: RedirectBuilder::new().build(),
811 })
812 .build(),
813 )
814 .build();
815 let left = r#"<WebsiteConfiguration><IndexDocument><Suffix>test</Suffix><SupportSubDir>true</SupportSubDir><Type>200</Type></IndexDocument><ErrorDocument><Key>abcd</Key><HttpStatus>404</HttpStatus></ErrorDocument><RoutingRules><RoutingRule><RuleNumber>100</RuleNumber><Condition/><Redirect><RedirectType>Mirror</RedirectType></Redirect></RoutingRule></RoutingRules></WebsiteConfiguration>"#;
816 let right = quick_xml::se::to_string(&config).unwrap();
817 assert_eq!(left, right);
818 }
819}