@@ -8,22 +8,58 @@ use stdx::default::default;
88pub struct VirtualHost < ' a > {
99 domain : Cow < ' a , str > ,
1010 bucket : Option < Cow < ' a , str > > ,
11- // pub(crate) region: Option<Cow<'a, str>>,
11+ region : Option < Cow < ' a , str > > ,
1212}
1313
1414impl < ' a > VirtualHost < ' a > {
1515 pub fn new ( domain : impl Into < Cow < ' a , str > > ) -> Self {
1616 Self {
1717 domain : domain. into ( ) ,
1818 bucket : None ,
19+ region : None ,
1920 }
2021 }
2122
22- pub fn with_bucket ( domain : impl Into < Cow < ' a , str > > , bucket : impl Into < Cow < ' a , str > > ) -> Self {
23- Self {
24- domain : domain. into ( ) ,
25- bucket : Some ( bucket. into ( ) ) ,
26- }
23+ /// Sets the bucket name for this virtual host.
24+ ///
25+ /// This method follows the builder pattern and returns `self` for method chaining.
26+ ///
27+ /// # Examples
28+ ///
29+ /// ```
30+ /// use s3s::host::VirtualHost;
31+ ///
32+ /// let vh = VirtualHost::new("example.com")
33+ /// .with_bucket("my-bucket");
34+ ///
35+ /// assert_eq!(vh.bucket(), Some("my-bucket"));
36+ /// ```
37+ #[ must_use]
38+ pub fn with_bucket ( mut self , bucket : impl Into < Cow < ' a , str > > ) -> Self {
39+ self . bucket = Some ( bucket. into ( ) ) ;
40+ self
41+ }
42+
43+ /// Sets the AWS region for this virtual host.
44+ ///
45+ /// This method follows the builder pattern and returns `self` for method chaining.
46+ /// The region represents the AWS region where the S3 bucket is located.
47+ ///
48+ /// # Examples
49+ ///
50+ /// ```
51+ /// use s3s::host::VirtualHost;
52+ ///
53+ /// let vh = VirtualHost::new("example.com")
54+ /// .with_bucket("my-bucket")
55+ /// .with_region("us-west-2");
56+ ///
57+ /// assert_eq!(vh.region(), Some("us-west-2"));
58+ /// ```
59+ #[ must_use]
60+ pub fn with_region ( mut self , region : impl Into < Cow < ' a , str > > ) -> Self {
61+ self . region = Some ( region. into ( ) ) ;
62+ self
2763 }
2864
2965 #[ inline]
@@ -37,6 +73,18 @@ impl<'a> VirtualHost<'a> {
3773 pub fn bucket ( & self ) -> Option < & str > {
3874 self . bucket . as_deref ( )
3975 }
76+
77+ /// Returns the AWS region associated with this virtual host, if set.
78+ ///
79+ /// # Returns
80+ ///
81+ /// - `Some(&str)` - The region name if it was set using `with_region()`
82+ /// - `None` - If no region was specified
83+ #[ inline]
84+ #[ must_use]
85+ pub fn region ( & self ) -> Option < & str > {
86+ self . region . as_deref ( )
87+ }
4088}
4189
4290pub trait S3Host : Send + Sync + ' static {
@@ -96,7 +144,7 @@ fn parse_host_header<'a>(base_domain: &'a str, host: &'a str) -> Option<VirtualH
96144 }
97145
98146 if let Some ( bucket) = host. strip_suffix ( base_domain) . and_then ( |h| h. strip_suffix ( '.' ) ) {
99- return Some ( VirtualHost :: with_bucket ( base_domain, bucket) ) ;
147+ return Some ( VirtualHost :: new ( base_domain) . with_bucket ( bucket) ) ;
100148 }
101149
102150 None
@@ -133,7 +181,7 @@ impl S3Host for SingleDomain {
133181
134182 if is_valid_domain ( host) {
135183 let bucket = host. to_ascii_lowercase ( ) ;
136- return Ok ( VirtualHost :: with_bucket ( host, bucket) ) ;
184+ return Ok ( VirtualHost :: new ( host) . with_bucket ( bucket) ) ;
137185 }
138186
139187 Err ( s3_error ! ( InvalidRequest , "Invalid host header" ) )
@@ -194,7 +242,7 @@ impl S3Host for MultiDomain {
194242
195243 if is_valid_domain ( host) {
196244 let bucket = host. to_ascii_lowercase ( ) ;
197- return Ok ( VirtualHost :: with_bucket ( host, bucket) ) ;
245+ return Ok ( VirtualHost :: new ( host) . with_bucket ( bucket) ) ;
198246 }
199247
200248 Err ( s3_error ! ( InvalidRequest , "Invalid host header" ) )
@@ -291,4 +339,41 @@ mod tests {
291339 assert_eq ! ( vh. domain( ) , "example.com" ) ;
292340 assert_eq ! ( vh. bucket( ) , Some ( "example.com.org" ) ) ;
293341 }
342+
343+ #[ test]
344+ fn virtual_host_builder ( ) {
345+ // Test basic construction
346+ let vh = VirtualHost :: new ( "example.com" ) ;
347+ assert_eq ! ( vh. domain( ) , "example.com" ) ;
348+ assert_eq ! ( vh. bucket( ) , None ) ;
349+ assert_eq ! ( vh. region( ) , None ) ;
350+
351+ // Test with_bucket builder
352+ let vh = VirtualHost :: new ( "example.com" ) . with_bucket ( "my-bucket" ) ;
353+ assert_eq ! ( vh. domain( ) , "example.com" ) ;
354+ assert_eq ! ( vh. bucket( ) , Some ( "my-bucket" ) ) ;
355+ assert_eq ! ( vh. region( ) , None ) ;
356+
357+ // Test with_region builder
358+ let vh = VirtualHost :: new ( "example.com" ) . with_region ( "us-west-2" ) ;
359+ assert_eq ! ( vh. domain( ) , "example.com" ) ;
360+ assert_eq ! ( vh. bucket( ) , None ) ;
361+ assert_eq ! ( vh. region( ) , Some ( "us-west-2" ) ) ;
362+
363+ // Test chaining with_bucket and with_region
364+ let vh = VirtualHost :: new ( "example.com" )
365+ . with_bucket ( "my-bucket" )
366+ . with_region ( "us-east-1" ) ;
367+ assert_eq ! ( vh. domain( ) , "example.com" ) ;
368+ assert_eq ! ( vh. bucket( ) , Some ( "my-bucket" ) ) ;
369+ assert_eq ! ( vh. region( ) , Some ( "us-east-1" ) ) ;
370+
371+ // Test chaining with_region and with_bucket (reversed order)
372+ let vh = VirtualHost :: new ( "example.com" )
373+ . with_region ( "eu-west-1" )
374+ . with_bucket ( "another-bucket" ) ;
375+ assert_eq ! ( vh. domain( ) , "example.com" ) ;
376+ assert_eq ! ( vh. bucket( ) , Some ( "another-bucket" ) ) ;
377+ assert_eq ! ( vh. region( ) , Some ( "eu-west-1" ) ) ;
378+ }
294379}
0 commit comments