1/*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 */
14
15package responses
16
17import (
18	"bytes"
19	"encoding/xml"
20	"fmt"
21	"io/ioutil"
22	"net/http"
23	"strings"
24
25	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
26	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils"
27)
28
29type AcsResponse interface {
30	IsSuccess() bool
31	GetHttpStatus() int
32	GetHttpHeaders() map[string][]string
33	GetHttpContentString() string
34	GetHttpContentBytes() []byte
35	GetOriginHttpResponse() *http.Response
36	parseFromHttpResponse(httpResponse *http.Response) error
37}
38
39var debug utils.Debug
40
41func init() {
42	debug = utils.Init("sdk")
43}
44// Unmarshal object from http response body to target Response
45func Unmarshal(response AcsResponse, httpResponse *http.Response, format string) (err error) {
46	err = response.parseFromHttpResponse(httpResponse)
47	if err != nil {
48		return
49	}
50	if !response.IsSuccess() {
51		err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), "")
52		return
53	}
54
55	if _, isCommonResponse := response.(*CommonResponse); isCommonResponse {
56		// common response need not unmarshal
57		return
58	}
59
60	if len(response.GetHttpContentBytes()) == 0 {
61		return
62	}
63
64	if strings.ToUpper(format) == "JSON" {
65		initJsonParserOnce()
66		err = jsonParser.Unmarshal(response.GetHttpContentBytes(), response)
67		if err != nil {
68			err = errors.NewClientError(errors.JsonUnmarshalErrorCode, errors.JsonUnmarshalErrorMessage, err)
69		}
70	} else if strings.ToUpper(format) == "XML" {
71		err = xml.Unmarshal(response.GetHttpContentBytes(), response)
72	}
73	return
74}
75
76type BaseResponse struct {
77	httpStatus         int
78	httpHeaders        map[string][]string
79	httpContentString  string
80	httpContentBytes   []byte
81	originHttpResponse *http.Response
82}
83
84func (baseResponse *BaseResponse) GetHttpStatus() int {
85	return baseResponse.httpStatus
86}
87
88func (baseResponse *BaseResponse) GetHttpHeaders() map[string][]string {
89	return baseResponse.httpHeaders
90}
91
92func (baseResponse *BaseResponse) GetHttpContentString() string {
93	return baseResponse.httpContentString
94}
95
96func (baseResponse *BaseResponse) GetHttpContentBytes() []byte {
97	return baseResponse.httpContentBytes
98}
99
100func (baseResponse *BaseResponse) GetOriginHttpResponse() *http.Response {
101	return baseResponse.originHttpResponse
102}
103
104func (baseResponse *BaseResponse) IsSuccess() bool {
105	if baseResponse.GetHttpStatus() >= 200 && baseResponse.GetHttpStatus() < 300 {
106		return true
107	}
108
109	return false
110}
111
112func (baseResponse *BaseResponse) parseFromHttpResponse(httpResponse *http.Response) (err error) {
113	defer httpResponse.Body.Close()
114	body, err := ioutil.ReadAll(httpResponse.Body)
115	if err != nil {
116		return
117	}
118	debug("%s", string(body))
119	baseResponse.httpStatus = httpResponse.StatusCode
120	baseResponse.httpHeaders = httpResponse.Header
121	baseResponse.httpContentBytes = body
122	baseResponse.httpContentString = string(body)
123	baseResponse.originHttpResponse = httpResponse
124	return
125}
126
127func (baseResponse *BaseResponse) String() string {
128	resultBuilder := bytes.Buffer{}
129	// statusCode
130	// resultBuilder.WriteString("\n")
131	resultBuilder.WriteString(fmt.Sprintf("%s %s\n", baseResponse.originHttpResponse.Proto, baseResponse.originHttpResponse.Status))
132	// httpHeaders
133	//resultBuilder.WriteString("Headers:\n")
134	for key, value := range baseResponse.httpHeaders {
135		resultBuilder.WriteString(key + ": " + strings.Join(value, ";") + "\n")
136	}
137	resultBuilder.WriteString("\n")
138	// content
139	//resultBuilder.WriteString("Content:\n")
140	resultBuilder.WriteString(baseResponse.httpContentString + "\n")
141	return resultBuilder.String()
142}
143
144type CommonResponse struct {
145	*BaseResponse
146}
147
148func NewCommonResponse() (response *CommonResponse) {
149	return &CommonResponse{
150		BaseResponse: &BaseResponse{},
151	}
152}
153