From 2f480cee685df99a8b183b94a7152a80fb4e14a8 Mon Sep 17 00:00:00 2001
From: jojo <agin719@126.com>
Date: Tue, 20 Aug 2019 20:19:22 +0800
Subject: [PATCH] add bucket website and domain interface

---
 bucket_domain.go             |  39 ++++++++++
 bucket_domain_test.go        | 113 +++++++++++++++++++++++++++++
 bucket_website.go            |  59 +++++++++++++++
 bucket_website_test.go       | 166 +++++++++++++++++++++++++++++++++++++++++++
 costesting/ci_test.go        |  40 ++++++++++-
 example/bucket/delWebsite.go |  35 +++++++++
 example/bucket/getDomain.go  |  35 +++++++++
 example/bucket/getWebsite.go |  35 +++++++++
 example/bucket/putDomain.go  |  42 +++++++++++
 example/bucket/putWebsite.go |  53 ++++++++++++++
 10 files changed, 614 insertions(+), 3 deletions(-)
 create mode 100644 bucket_domain.go
 create mode 100644 bucket_domain_test.go
 create mode 100644 bucket_website.go
 create mode 100644 bucket_website_test.go
 create mode 100644 example/bucket/delWebsite.go
 create mode 100644 example/bucket/getDomain.go
 create mode 100644 example/bucket/getWebsite.go
 create mode 100644 example/bucket/putDomain.go
 create mode 100644 example/bucket/putWebsite.go

diff --git a/bucket_domain.go b/bucket_domain.go
new file mode 100644
index 0000000..87f78b6
--- /dev/null
+++ b/bucket_domain.go
@@ -0,0 +1,39 @@
+package cos
+
+import (
+	"context"
+	"encoding/xml"
+	"net/http"
+)
+
+type BucketPutDomainOptions struct {
+	XMLName           xml.Name `xml:"DomainConfiguration"`
+	Status            string   `xml:"DomainRule>Status,omitempty"`
+	Name              string   `xml:"DomainRule>Name,omitempty"`
+	Type              string   `xml:"DomainRule>Type,omitempty"`
+	ForcedReplacement string   `xml:"DomainRule>ForcedReplacement,omitempty"`
+}
+type BucketGetDomainResult BucketPutDomainOptions
+
+func (s *BucketService) PutDomain(ctx context.Context, opt *BucketPutDomainOptions) (*Response, error) {
+	sendOpt := &sendOptions{
+		baseURL: s.client.BaseURL.BucketURL,
+		uri:     "/?domain",
+		method:  http.MethodPut,
+		body:    opt,
+	}
+	resp, err := s.client.send(ctx, sendOpt)
+	return resp, err
+}
+
+func (s *BucketService) GetDomain(ctx context.Context) (*BucketGetDomainResult, *Response, error) {
+	var res BucketGetDomainResult
+	sendOpt := &sendOptions{
+		baseURL: s.client.BaseURL.BucketURL,
+		uri:     "/?domain",
+		method:  http.MethodGet,
+		result:  &res,
+	}
+	resp, err := s.client.send(ctx, sendOpt)
+	return &res, resp, err
+}
diff --git a/bucket_domain_test.go b/bucket_domain_test.go
new file mode 100644
index 0000000..896e68f
--- /dev/null
+++ b/bucket_domain_test.go
@@ -0,0 +1,113 @@
+package cos
+
+import (
+	"context"
+	"encoding/xml"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestBucketService_GetDomain(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		vs := values{
+			"domain": "",
+		}
+		testFormValues(t, r, vs)
+		fmt.Fprint(w, `<DomainConfiguration>
+  	<DomainRule>
+    	<Status>ENABLED</Status>
+	    <Name>www.abc.com</Name>
+		<Type>REST</Type>
+		<ForcedReplacement>CNAME</ForcedReplacement>
+	</DomainRule>
+</DomainConfiguration>`)
+	})
+
+	res, _, err := client.Bucket.GetDomain(context.Background())
+	if err != nil {
+		t.Fatalf("Bucket.GetDomain returned error %v", err)
+	}
+
+	want := &BucketGetDomainResult{
+		XMLName:           xml.Name{Local: "DomainConfiguration"},
+		Status:            "ENABLED",
+		Name:              "www.abc.com",
+		Type:              "REST",
+		ForcedReplacement: "CNAME",
+	}
+
+	if !reflect.DeepEqual(res, want) {
+		t.Errorf("Bucket.GetDomain returned %+v, want %+v", res, want)
+	}
+}
+
+func TestBucketService_PutDomain(t *testing.T) {
+	setup()
+	defer teardown()
+
+	opt := &BucketPutDomainOptions{
+		XMLName:           xml.Name{Local: "DomainConfiguration"},
+		Status:            "ENABLED",
+		Name:              "www.abc.com",
+		Type:              "REST",
+		ForcedReplacement: "CNAME",
+	}
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+		vs := values{
+			"domain": "",
+		}
+		testFormValues(t, r, vs)
+
+		body := new(BucketPutDomainOptions)
+		xml.NewDecoder(r.Body).Decode(body)
+		want := opt
+		want.XMLName = xml.Name{Local: "DomainConfiguration"}
+		if !reflect.DeepEqual(body, want) {
+			t.Errorf("Bucket.PutDomain request\n body: %+v\n, want %+v\n", body, want)
+		}
+	})
+
+	_, err := client.Bucket.PutDomain(context.Background(), opt)
+	if err != nil {
+		t.Fatalf("Bucket.PutDomain returned error: %v", err)
+	}
+}
+
+func TestBucketService_DeleteDomain(t *testing.T) {
+	setup()
+	defer teardown()
+
+	opt := &BucketPutDomainOptions{}
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodPut)
+		vs := values{
+			"domain": "",
+		}
+		testFormValues(t, r, vs)
+
+		body := new(BucketPutDomainOptions)
+		xml.NewDecoder(r.Body).Decode(body)
+		want := opt
+		want.XMLName = xml.Name{Local: "DomainConfiguration"}
+		if !reflect.DeepEqual(body, want) {
+			t.Errorf("Bucket.PutDomain request\n body: %+v\n, want %+v\n", body, want)
+		}
+
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	_, err := client.Bucket.PutDomain(context.Background(), opt)
+	if err != nil {
+		t.Fatalf("Bucket.PutDomain returned error: %v", err)
+	}
+
+}
diff --git a/bucket_website.go b/bucket_website.go
new file mode 100644
index 0000000..3052bf1
--- /dev/null
+++ b/bucket_website.go
@@ -0,0 +1,59 @@
+package cos
+
+import (
+	"context"
+	"encoding/xml"
+	"net/http"
+)
+
+type WebsiteRoutingRule struct {
+	ConditionErrorCode string `xml:"Condition>HttpErrorCodeReturnedEquals,omitempty"`
+	ConditionPrefix    string `xml:"Condition>KeyPrefixEquals,omitempty"`
+
+	RedirectProtocol         string `xml:"Redirect>Protocol,omitempty"`
+	RedirectReplaceKey       string `xml:"Redirect>ReplaceKeyWith,omitempty"`
+	RedirectReplaceKeyPrefix string `xml:"Redirect>ReplaceKeyPrefixWith,omitempty"`
+}
+
+type BucketPutWebsiteOptions struct {
+	XMLName          xml.Name             `xml:"WebsiteConfiguration"`
+	Index            string               `xml:"IndexDocument>Suffix"`
+	RedirectProtocol string               `xml:"RedirectAllRequestsTo>Protocol,omitempty"`
+	Error            string               `xml:"ErrorDocument>Key,omitempty"`
+	Rules            []WebsiteRoutingRule `xml:"RoutingRules>RoutingRule,omitempty"`
+}
+
+type BucketGetWebsiteResult BucketPutWebsiteOptions
+
+func (s *BucketService) PutWebsite(ctx context.Context, opt *BucketPutWebsiteOptions) (*Response, error) {
+	sendOpt := &sendOptions{
+		baseURL: s.client.BaseURL.BucketURL,
+		uri:     "/?website",
+		method:  http.MethodPut,
+		body:    opt,
+	}
+	resp, err := s.client.send(ctx, sendOpt)
+	return resp, err
+}
+
+func (s *BucketService) GetWebsite(ctx context.Context) (*BucketGetWebsiteResult, *Response, error) {
+	var res BucketGetWebsiteResult
+	sendOpt := &sendOptions{
+		baseURL: s.client.BaseURL.BucketURL,
+		uri:     "/?website",
+		method:  http.MethodGet,
+		result:  &res,
+	}
+	resp, err := s.client.send(ctx, sendOpt)
+	return &res, resp, err
+}
+
+func (s *BucketService) DeleteWebsite(ctx context.Context) (*Response, error) {
+	sendOpt := &sendOptions{
+		baseURL: s.client.BaseURL.BucketURL,
+		uri:     "/?website",
+		method:  http.MethodDelete,
+	}
+	resp, err := s.client.send(ctx, sendOpt)
+	return resp, err
+}
diff --git a/bucket_website_test.go b/bucket_website_test.go
new file mode 100644
index 0000000..c59bcc8
--- /dev/null
+++ b/bucket_website_test.go
@@ -0,0 +1,166 @@
+package cos
+
+import (
+	"context"
+	"encoding/xml"
+	"fmt"
+	"net/http"
+	"reflect"
+	"testing"
+)
+
+func TestBucketService_GetWebsite(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "GET")
+		vs := values{
+			"website": "",
+		}
+		testFormValues(t, r, vs)
+		fmt.Fprint(w, `<WebsiteConfiguration>
+	<IndexDocument>
+		<Suffix>index.html</Suffix>
+	</IndexDocument>
+	<RedirectAllRequestsTo>
+		<Protocol>https</Protocol>
+	</RedirectAllRequestsTo>
+	<ErrorDocument>
+		<Key>Error.html</Key>
+	</ErrorDocument>
+	<RoutingRules>
+		<RoutingRule>
+			<Condition>
+				<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
+			</Condition>
+			<Redirect>
+				<Protocol>https</Protocol>
+				<ReplaceKeyWith>404.html</ReplaceKeyWith>
+			</Redirect>
+		</RoutingRule>
+		<RoutingRule>
+			<Condition>
+				<KeyPrefixEquals>docs/</KeyPrefixEquals>
+			</Condition>
+			<Redirect>
+				<Protocol>https</Protocol>
+				<ReplaceKeyPrefixWith>documents/</ReplaceKeyPrefixWith>
+			</Redirect>
+		</RoutingRule>
+		<RoutingRule>
+			<Condition>
+				<KeyPrefixEquals>img/</KeyPrefixEquals>
+			</Condition>
+			<Redirect>
+				<Protocol>https</Protocol>
+				<ReplaceKeyWith>demo.jpg</ReplaceKeyWith>
+			</Redirect>
+		</RoutingRule>
+	</RoutingRules>
+</WebsiteConfiguration>`)
+	})
+
+	res, _, err := client.Bucket.GetWebsite(context.Background())
+	if err != nil {
+		t.Fatalf("Bucket.GetWebsite returned error %v", err)
+	}
+
+	want := &BucketGetWebsiteResult{
+		XMLName:          xml.Name{Local: "WebsiteConfiguration"},
+		Index:            "index.html",
+		RedirectProtocol: "https",
+		Error:            "Error.html",
+		Rules: []WebsiteRoutingRule{
+			{
+				ConditionErrorCode: "404",
+				RedirectProtocol:   "https",
+				RedirectReplaceKey: "404.html",
+			},
+			{
+				ConditionPrefix:          "docs/",
+				RedirectProtocol:         "https",
+				RedirectReplaceKeyPrefix: "documents/",
+			},
+			{
+				ConditionPrefix:    "img/",
+				RedirectProtocol:   "https",
+				RedirectReplaceKey: "demo.jpg",
+			},
+		},
+	}
+
+	if !reflect.DeepEqual(res, want) {
+		t.Errorf("Bucket.GetWebsite returned %+v, want %+v", res, want)
+	}
+}
+
+func TestBucketService_PutWebsite(t *testing.T) {
+	setup()
+	defer teardown()
+
+	opt := &BucketPutWebsiteOptions{
+		Index:            "index.html",
+		RedirectProtocol: "https",
+		Error:            "Error.html",
+		Rules: []WebsiteRoutingRule{
+			{
+				ConditionErrorCode: "404",
+				RedirectProtocol:   "https",
+				RedirectReplaceKey: "404.html",
+			},
+			{
+				ConditionPrefix:          "docs/",
+				RedirectProtocol:         "https",
+				RedirectReplaceKeyPrefix: "documents/",
+			},
+			{
+				ConditionPrefix:    "img/",
+				RedirectProtocol:   "https",
+				RedirectReplaceKey: "demo.jpg",
+			},
+		},
+	}
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, "PUT")
+		vs := values{
+			"website": "",
+		}
+		testFormValues(t, r, vs)
+
+		body := new(BucketPutWebsiteOptions)
+		xml.NewDecoder(r.Body).Decode(body)
+		want := opt
+		want.XMLName = xml.Name{Local: "WebsiteConfiguration"}
+		if !reflect.DeepEqual(body, want) {
+			t.Errorf("Bucket.PutWebsite request\n body: %+v\n, want %+v\n", body, want)
+		}
+	})
+
+	_, err := client.Bucket.PutWebsite(context.Background(), opt)
+	if err != nil {
+		t.Fatalf("Bucket.PutWebsite returned error: %v", err)
+	}
+}
+
+func TestBucketService_DeleteWebsite(t *testing.T) {
+	setup()
+	defer teardown()
+
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		testMethod(t, r, http.MethodDelete)
+		vs := values{
+			"website": "",
+		}
+		testFormValues(t, r, vs)
+
+		w.WriteHeader(http.StatusNoContent)
+	})
+
+	_, err := client.Bucket.DeleteWebsite(context.Background())
+	if err != nil {
+		t.Fatalf("Bucket.DeleteWebsite returned error: %v", err)
+	}
+
+}
diff --git a/costesting/ci_test.go b/costesting/ci_test.go
index ea2dc59..8e485ee 100644
--- a/costesting/ci_test.go
+++ b/costesting/ci_test.go
@@ -4,9 +4,6 @@ package cos
 import (
 	"context"
 	"fmt"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/suite"
-	"github.com/tencentyun/cos-go-sdk-v5"
 	"io/ioutil"
 	"math/rand"
 	"net/http"
@@ -15,6 +12,10 @@ import (
 	"strings"
 	"testing"
 	"time"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/suite"
+	"github.com/tencentyun/cos-go-sdk-v5"
 )
 
 // Define the suite, and absorb the built-in basic suite
@@ -304,6 +305,39 @@ func (s *CosTestSuite) TestPutGetDeleteLifeCycle() {
 	assert.Nil(s.T(), err, "DeleteBucketLifecycle Failed")
 }
 
+func (s *CosTestSuite) TestPutGetDeleteWebsite() {
+	opt := &cos.BucketPutWebsiteOptions{
+		Index:            "index.html",
+		Error:            "index_backup.html",
+		RedirectProtocol: "https",
+		Rules: []cos.WebsiteRoutingRule{
+			{
+				ConditionErrorCode: "404",
+				RedirectProtocol:   "https",
+				RedirectReplaceKey: "404.html",
+			},
+			{
+				ConditionPrefix:          "docs/",
+				RedirectProtocol:         "https",
+				RedirectReplaceKeyPrefix: "documents/",
+			},
+		},
+	}
+
+	_, err := s.Client.Bucket.PutWebsite(context.Background(), opt)
+	assert.Nil(s.T(), err, "PutBucketWebsite Failed")
+
+	res, rsp, err := s.Client.Bucket.GetWebsite(context.Background())
+	if err != nil && 404 != rsp.StatusCode {
+		assert.Nil(s.T(), err, "GetBucketWebsite Failed")
+	}
+	assert.Equal(s.T(), opt.Index, res.Index, "GetBucketWebsite Failed")
+	assert.Equal(s.T(), opt.Error, res.Error, "GetBucketWebsite Failed")
+	assert.Equal(s.T(), opt.RedirectProtocol, res.RedirectProtocol, "GetBucketWebsite Failed")
+	_, err = s.Client.Bucket.DeleteWebsite(context.Background())
+	assert.Nil(s.T(), err, "DeleteBucketWebsite Failed")
+}
+
 func (s *CosTestSuite) TestListMultipartUploads() {
 	// Create new upload
 	name := "test_multipart" + time.Now().Format(time.RFC3339)
diff --git a/example/bucket/delWebsite.go b/example/bucket/delWebsite.go
new file mode 100644
index 0000000..4741490
--- /dev/null
+++ b/example/bucket/delWebsite.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"os"
+
+	"github.com/tencentyun/cos-go-sdk-v5"
+	"github.com/tencentyun/cos-go-sdk-v5/debug"
+)
+
+func main() {
+	u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
+	b := &cos.BaseURL{
+		BucketURL: u,
+	}
+	c := cos.NewClient(b, &http.Client{
+		Transport: &cos.AuthorizationTransport{
+			SecretID:  os.Getenv("COS_SECRETID"),
+			SecretKey: os.Getenv("COS_SECRETKEY"),
+			Transport: &debug.DebugRequestTransport{
+				RequestHeader:  true,
+				RequestBody:    true,
+				ResponseHeader: true,
+				ResponseBody:   true,
+			},
+		},
+	})
+
+	_, err := c.Bucket.DeleteWebsite(context.Background())
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/example/bucket/getDomain.go b/example/bucket/getDomain.go
new file mode 100644
index 0000000..0de5e0d
--- /dev/null
+++ b/example/bucket/getDomain.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"os"
+
+	"github.com/tencentyun/cos-go-sdk-v5"
+	"github.com/tencentyun/cos-go-sdk-v5/debug"
+)
+
+func main() {
+	u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
+	b := &cos.BaseURL{
+		BucketURL: u,
+	}
+	c := cos.NewClient(b, &http.Client{
+		Transport: &cos.AuthorizationTransport{
+			SecretID:  os.Getenv("COS_SECRETID"),
+			SecretKey: os.Getenv("COS_SECRETKEY"),
+			Transport: &debug.DebugRequestTransport{
+				RequestHeader:  true,
+				RequestBody:    true,
+				ResponseHeader: true,
+				ResponseBody:   true,
+			},
+		},
+	})
+
+	_, _, err := c.Bucket.GetDomain(context.Background())
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/example/bucket/getWebsite.go b/example/bucket/getWebsite.go
new file mode 100644
index 0000000..78b82c4
--- /dev/null
+++ b/example/bucket/getWebsite.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"os"
+
+	"github.com/tencentyun/cos-go-sdk-v5"
+	"github.com/tencentyun/cos-go-sdk-v5/debug"
+)
+
+func main() {
+	u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
+	b := &cos.BaseURL{
+		BucketURL: u,
+	}
+	c := cos.NewClient(b, &http.Client{
+		Transport: &cos.AuthorizationTransport{
+			SecretID:  os.Getenv("COS_SECRETID"),
+			SecretKey: os.Getenv("COS_SECRETKEY"),
+			Transport: &debug.DebugRequestTransport{
+				RequestHeader:  true,
+				RequestBody:    true,
+				ResponseHeader: true,
+				ResponseBody:   true,
+			},
+		},
+	})
+
+	_, _, err := c.Bucket.GetWebsite(context.Background())
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/example/bucket/putDomain.go b/example/bucket/putDomain.go
new file mode 100644
index 0000000..e14968b
--- /dev/null
+++ b/example/bucket/putDomain.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"os"
+
+	"github.com/tencentyun/cos-go-sdk-v5"
+	"github.com/tencentyun/cos-go-sdk-v5/debug"
+)
+
+func main() {
+	u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
+	b := &cos.BaseURL{
+		BucketURL: u,
+	}
+	c := cos.NewClient(b, &http.Client{
+		Transport: &cos.AuthorizationTransport{
+			SecretID:  os.Getenv("COS_SECRETID"),
+			SecretKey: os.Getenv("COS_SECRETKEY"),
+			Transport: &debug.DebugRequestTransport{
+				RequestHeader:  true,
+				RequestBody:    true,
+				ResponseHeader: true,
+				ResponseBody:   true,
+			},
+		},
+	})
+
+	opt := &cos.BucketPutDomainOptions{
+		Status:            "ENABLED",
+		Name:              "www.abc.com",
+		Type:              "REST",
+		ForcedReplacement: "CNAME",
+	}
+
+	_, err := c.Bucket.PutDomain(context.Background(), opt)
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/example/bucket/putWebsite.go b/example/bucket/putWebsite.go
new file mode 100644
index 0000000..c87fb23
--- /dev/null
+++ b/example/bucket/putWebsite.go
@@ -0,0 +1,53 @@
+package main
+
+import (
+	"context"
+	"net/http"
+	"net/url"
+	"os"
+
+	"github.com/tencentyun/cos-go-sdk-v5"
+	"github.com/tencentyun/cos-go-sdk-v5/debug"
+)
+
+func main() {
+	u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com")
+	b := &cos.BaseURL{
+		BucketURL: u,
+	}
+	c := cos.NewClient(b, &http.Client{
+		Transport: &cos.AuthorizationTransport{
+			SecretID:  os.Getenv("COS_SECRETID"),
+			SecretKey: os.Getenv("COS_SECRETKEY"),
+			Transport: &debug.DebugRequestTransport{
+				RequestHeader:  true,
+				RequestBody:    true,
+				ResponseHeader: true,
+				ResponseBody:   true,
+			},
+		},
+	})
+
+	opt := &cos.BucketPutWebsiteOptions{
+		Index:            "index.html",
+		Error:            "index_backup.html",
+		RedirectProtocol: "https",
+		Rules: []cos.WebsiteRoutingRule{
+			{
+				ConditionErrorCode: "404",
+				RedirectProtocol:   "https",
+				RedirectReplaceKey: "404.html",
+			},
+			{
+				ConditionPrefix:          "docs/",
+				RedirectProtocol:         "https",
+				RedirectReplaceKeyPrefix: "documents/",
+			},
+		},
+	}
+
+	_, err := c.Bucket.PutWebsite(context.Background(), opt)
+	if err != nil {
+		panic(err)
+	}
+}