Browse Source

Merge pull request #41 from aliyun/test

publish 0.11.1
gaort 7 years ago
parent
commit
e399f6b46b

+ 3 - 0
sdk/auth/roa_signature_composer.go

@@ -25,6 +25,7 @@ import (
 func signRoaRequest(request requests.AcsRequest, signer Signer, regionId string) {
 	completeROASignParams(request, signer, regionId)
 	stringToSign := buildRoaStringToSign(request)
+	request.SetStringToSign(stringToSign)
 	signature := signer.Sign(stringToSign, "")
 	request.GetHeaders()["Authorization"] = "acs " + signer.GetAccessKeyId() + ":" + signature
 }
@@ -99,6 +100,8 @@ func buildRoaStringToSign(request requests.AcsRequest) (stringToSign string) {
 	return
 }
 
+
+
 func appendIfContain(sourceMap map[string]string, target *bytes.Buffer, key, separator string) {
 	if value, contain := sourceMap[key]; contain && len(value) > 0 {
 		target.WriteString(sourceMap[key])

+ 1 - 0
sdk/auth/rpc_signature_composer.go

@@ -29,6 +29,7 @@ func signRpcRequest(request requests.AcsRequest, signer Signer, regionId string)
 		delete(request.GetQueryParams(), "Signature")
 	}
 	stringToSign := buildRpcStringToSign(request)
+	request.SetStringToSign(stringToSign)
 	signature := signer.Sign(stringToSign, "&")
 	request.GetQueryParams()["Signature"] = signature
 }

+ 2 - 2
sdk/auth/signers/signer_key_pair.go

@@ -118,8 +118,8 @@ func (signerKeyPair *SignerKeyPair) refreshApi(request *requests.CommonRequest)
 
 func (signer *SignerKeyPair) refreshCredential(response *responses.CommonResponse) (err error) {
 	if response.GetHttpStatus() != http.StatusOK {
-		message := "refresh session AccessKey failed, message = " + response.GetHttpContentString()
-		err = errors.NewServerError(response.GetHttpStatus(), response.GetOriginHttpResponse().Status, message)
+		message := "refresh session AccessKey failed"
+		err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), message)
 		if signer.sessionCredential == nil {
 			panic(err)
 		}

+ 2 - 2
sdk/auth/signers/signer_ram_role_arn.go

@@ -135,8 +135,8 @@ func (signerStsAssumeRole *RamRoleArnSigner) refreshApi(request *requests.Common
 
 func (signer *RamRoleArnSigner) refreshCredential(response *responses.CommonResponse) (err error) {
 	if response.GetHttpStatus() != http.StatusOK {
-		message := "refresh session token failed, message = " + response.GetHttpContentString()
-		err = errors.NewServerError(response.GetHttpStatus(), response.GetOriginHttpResponse().Status, message)
+		message := "refresh session token failed"
+		err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), message)
 		if signer.sessionCredential == nil {
 			panic(err)
 		}

+ 6 - 0
sdk/client.go

@@ -222,6 +222,12 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 		break
 	}
 	err = responses.Unmarshal(response, httpResponse, request.GetAcceptFormat())
+	// wrap server errors
+	if serverErr, ok := err.(*errors.ServerError); ok {
+		var wrapInfo = map[string]string{}
+		wrapInfo["StringToSign"] = request.GetStringToSign()
+		err = errors.WrapServerError(serverErr, wrapInfo)
+	}
 	return
 }
 

+ 80 - 9
sdk/errors/server_error.go

@@ -14,20 +14,79 @@
 
 package errors
 
-import "fmt"
+import (
+	"fmt"
+	"encoding/json"
+	"github.com/jmespath/go-jmespath"
+)
+
+var wrapperList = []ServerErrorWrapper{
+	&SignatureDostNotMatchWrapper{},
+}
 
 type ServerError struct {
 	httpStatus int
+	requestId  string
+	hostId     string
 	errorCode  string
+	recommend  string
 	message    string
+	comment    string
+}
+
+type ServerErrorWrapper interface {
+	tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError)
+}
+
+func (err *ServerError) Error() string {
+	return fmt.Sprintf("SDK.ServerError\nErrorCode: %s\nRecommend: %s\nRequestId: %s\nMessage: %s",
+		err.errorCode, err.comment+err.recommend, err.requestId, err.message)
 }
 
-func NewServerError(httpStatus int, errorCode, message string) Error {
-	return &ServerError{
+func NewServerError(httpStatus int, responseContent, comment string) Error {
+	result := &ServerError{
 		httpStatus: httpStatus,
-		errorCode:  errorCode,
-		message:    message,
+		message:    responseContent,
+		comment:    comment,
 	}
+
+	var data interface{}
+	err := json.Unmarshal([]byte(responseContent), &data)
+	if err == nil {
+		requestId, _ := jmespath.Search("RequestId", data)
+		hostId, _ := jmespath.Search("HostId", data)
+		errorCode, _ := jmespath.Search("Code", data)
+		recommend, _ := jmespath.Search("Recommend", data)
+		message, _ := jmespath.Search("Message", data)
+
+		if requestId != nil {
+			result.requestId = requestId.(string)
+		}
+		if hostId != nil {
+			result.hostId = hostId.(string)
+		}
+		if errorCode != nil {
+			result.errorCode = errorCode.(string)
+		}
+		if recommend != nil {
+			result.recommend = recommend.(string)
+		}
+		if message != nil {
+			result.message = message.(string)
+		}
+	}
+
+	return result
+}
+
+func WrapServerError(originError *ServerError, wrapInfo map[string]string) *ServerError {
+	for _, wrapper := range wrapperList {
+		ok, newError := wrapper.tryWrap(originError, wrapInfo)
+		if ok {
+			return newError
+		}
+	}
+	return originError
 }
 
 func (err *ServerError) HttpStatus() int {
@@ -42,10 +101,22 @@ func (err *ServerError) Message() string {
 	return err.message
 }
 
-func (err *ServerError) Error() string {
-	return fmt.Sprintf("SDK.ServerError %s %s", err.errorCode, err.message)
-}
-
 func (err *ServerError) OriginError() error {
 	return nil
 }
+
+func (err *ServerError) HostId() string {
+	return err.hostId
+}
+
+func (err *ServerError) RequestId() string {
+	return err.requestId
+}
+
+func (err *ServerError) Recommend() string {
+	return err.recommend
+}
+
+func (err *ServerError) Comment() string {
+	return err.comment
+}

+ 29 - 0
sdk/errors/signature_does_not_match_wrapper.go

@@ -0,0 +1,29 @@
+package errors
+
+import "strings"
+
+const SignatureDostNotMatchErrorCode = "SignatureDoesNotMatch"
+const MessagePrefix = "Specified signature is not matched with our calculation. server string to sign is:"
+
+type SignatureDostNotMatchWrapper struct {
+}
+
+func (*SignatureDostNotMatchWrapper) tryWrap(error *ServerError, wrapInfo map[string]string) (bool, *ServerError) {
+	clientStringToSign := wrapInfo["StringToSign"]
+	if error.errorCode == SignatureDostNotMatchErrorCode && clientStringToSign != "" {
+		message := error.message
+		if strings.HasPrefix(message, MessagePrefix){
+			serverStringToSign := message[len(MessagePrefix):len(message)]
+			if clientStringToSign == serverStringToSign{
+				// user secret is error
+				error.recommend = "Please check you AccessKeySecret"
+			}else{
+				error.recommend = "This may be a bug with the SDK and we hope you can submit this question in the " +
+						"github issue(https://github.com/aliyun/alibaba-cloud-sdk-go/issues), thanks very much"
+			}
+		}
+		return true, error
+	} else {
+		return false, nil
+	}
+}

+ 13 - 0
sdk/requests/acs_reqeust.go

@@ -73,6 +73,9 @@ type AcsRequest interface {
 	GetLocationServiceCode() string
 	GetLocationEndpointType() string
 
+	SetStringToSign(stringToSign string)
+	GetStringToSign() string
+
 	SetDomain(domain string)
 	SetContent(content []byte)
 	BuildUrl() string
@@ -107,6 +110,8 @@ type baseRequest struct {
 	locationEndpointType string
 
 	queries string
+
+	stringToSign string
 }
 
 func (request *baseRequest) GetQueryParams() map[string]string {
@@ -198,6 +203,14 @@ func (request *baseRequest) GetContentType() (contentType string, contains bool)
 	return
 }
 
+func (request *baseRequest) SetStringToSign(stringToSign string) {
+	request.stringToSign = stringToSign
+}
+
+func (request *baseRequest) GetStringToSign() string {
+	return request.stringToSign
+}
+
 func defaultBaseRequest() (request *baseRequest) {
 	request = &baseRequest{
 		Scheme:       HTTP,

+ 23 - 3
sdk/requests/roa_request.go

@@ -20,6 +20,7 @@ import (
 	"io"
 	"sort"
 	"strings"
+	"net/url"
 )
 
 type RoaRequest struct {
@@ -47,7 +48,12 @@ func (request *RoaRequest) GetQueries() string {
 	return request.queries
 }
 
+// for sign method, need not url encoded
 func (request *RoaRequest) BuildQueries() string {
+	return request.buildQueries(false)
+}
+
+func (request *RoaRequest) buildQueries(needParamEncode bool) string {
 	// replace path params with value
 	path := request.pathPattern
 	for key, value := range request.PathParams {
@@ -77,22 +83,36 @@ func (request *RoaRequest) BuildQueries() string {
 		urlBuilder.WriteString(queryKey)
 		if value := queryParams[queryKey]; len(value) > 0 {
 			urlBuilder.WriteString("=")
-			urlBuilder.WriteString(value)
+			if needParamEncode{
+				urlBuilder.WriteString(url.QueryEscape(value))
+			}else{
+				urlBuilder.WriteString(value)
+			}
 		}
 		if i < len(queryKeys)-1 {
 			urlBuilder.WriteString("&")
 		}
 	}
-	request.queries = urlBuilder.String()
+	result := urlBuilder.String()
+	result = popStandardUrlencode(result)
+	request.queries = result
 	return request.queries
 }
 
+func popStandardUrlencode(stringToSign string)(result string){
+	result = strings.Replace(stringToSign, "+", "%20", -1)
+	result = strings.Replace(result, "*", "%2A", -1)
+	result = strings.Replace(result, "%7E", "~", -1)
+	return
+}
+
 func (request *RoaRequest) GetUrl() string {
 	return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.GetQueries()
 }
 
 func (request *RoaRequest) BuildUrl() string {
-	return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.BuildQueries()
+	// for network trans, need url encoded
+	return strings.ToLower(request.Scheme) + "://" + request.Domain + ":" + request.Port + request.buildQueries(true)
 }
 
 func (request *RoaRequest) addPathParam(key, value string) {

+ 1 - 1
sdk/responses/response.go

@@ -40,7 +40,7 @@ func Unmarshal(response AcsResponse, httpResponse *http.Response, format string)
 		return
 	}
 	if !response.IsSuccess() {
-		err = errors.NewServerError(response.GetHttpStatus(), response.GetOriginHttpResponse().Status, response.GetHttpContentString())
+		err = errors.NewServerError(response.GetHttpStatus(), response.GetHttpContentString(), "")
 		return
 	}
 	if _, isCommonResponse := response.(CommonResponse); isCommonResponse {