Browse Source

support https request to skip certificate check

wenzuochao 6 years ago
parent
commit
ce703c1bff
6 changed files with 118 additions and 7 deletions
  1. 24 5
      README.md
  2. 20 2
      README_zh.md
  3. 30 0
      sdk/client.go
  4. 28 0
      sdk/client_test.go
  5. 11 0
      sdk/requests/acs_request.go
  6. 5 0
      sdk/requests/acs_request_test.go

+ 24 - 5
README.md

@@ -94,11 +94,30 @@ func main() {
 
 When you create an instance of client, you need to fill out three parameters: `Region ID`、`Access Key ID` and `Access Key Secret`. You can get `Access Key ID` and `Access Key Secret` from console, and get `Region ID` from [region list](https://help.aliyun.com/document_detail/40654.html?spm=5176.doc52740.2.8.FogWrd)
 
-## Dubug
+## Debug
 
 If the request has occured an error, you can view the HTTP request process by adding the environment variable `DEBUG=sdk`.
 
+## Ignore certificate validation
+
+When you send a https request, it may be fail due to certificate validation. At this moment, you can use the way below to ignore certificate validation.
+
+```go
+// You can set HTTPSInsecure as true to ignore certificate validation.
+// Request HTTPSInsecure has a higher priority than client HTTPSInsecure.
+// If you don't set any HTTPSInsecure, the default HTTPSInsecure is false.
+
+// Set request HTTPSInsecure(Only the request is effected.)
+request.SetHTTPSInsecure(true)                           // Set request HTTPSInsecure to true.
+isInsecure := request.GetHTTPSInsecure()                 // Get request HTTPSInsecure.
+
+// Set client HTTPSInsecure(For all requests which is sent by the client.)
+client.SetHTTPSInsecure(true)                         // Set client HTTPSInsecure to true .
+isInsecure := client.GetHTTPSInsecure()               // Get client HTTPSInsecure.
+```
+
 ## Keep-alive
+
 Alibaba Cloud Go SDK uses primordial `net/http` of Go language to send and accept requests,so it's  configuration is the same as `net/http`'s,you can use config to deliver configuration to the bottomed httpClient.
 
 ```go
@@ -123,16 +142,16 @@ ecsClient, err := ecs.NewClientWithOptions(config)
 // If you don't set any timeout, the default ReadTimeout is 10 second, and the default ConnectTimeout is 5 second.
 
 // Set request Timeout(Only the request is effected.)
-request.SetReadTimeout(10 * time.Second)              // Set request ReadTimeout to 10 second.
+request.SetReadTimeout(10 * time.Second)             // Set request ReadTimeout to 10 second.
 readTimeout := request.GetReadTimeout()              // Get request ReadTimeout.
 request.SetConnectTimeout(5 * time.Second)           // Set request ConnectTimeout to 5 second.
 connectTimeout := request.GetConnectTimeout()        // Get request ConnectTimeout.
 
 // Set client Timeout(For all requests which is sent by the client.)
 client.SetReadTimeout(10 * time.Second)              // Set client ReadTimeout to 10 second.
-readTimeout := client.GetReadTimeout()              // Get client ReadTimeout.
-client.SetConnectTimeout(5 * time.Second)           // Set client ConnectTimeout to 5 second.
-connectTimeout := client.GetConnectTimeout()        // Get client ConnectTimeout.
+readTimeout := client.GetReadTimeout()               // Get client ReadTimeout.
+client.SetConnectTimeout(5 * time.Second)            // Set client ConnectTimeout to 5 second.
+connectTimeout := client.GetConnectTimeout()         // Get client ConnectTimeout.
 ```
 
 ### Open SDK Client's concurrent function.

+ 20 - 2
README_zh.md

@@ -85,12 +85,30 @@ func main() {
 
 在创建Client实例时,您需要填写3个参数:`Region ID`、`Access Key ID`和`Access Key Secret`。`Access Key ID`和`Access Key Secret`可以从控制台获得;而`Region ID`可以从[地域列表](https://help.aliyun.com/document_detail/40654.html?spm=5176.doc52740.2.8.FogWrd)中获得
 
-## Debug
+## 调试
 
 如果您发送的请求出错,您可以通过添加环境变量 `DEBUG=sdk` 来查看 HTTP 请求过程。
 
+## 忽略安全证书校验
+
+当您发送 https 请求时,它可能由于证书校验而失败。此时,可以使用下面的方法来忽略证书校验。
+
+```go
+// 您可以将 HTTPSInsecure 设置为 true 以忽略证书验证
+// 请求 HTTPSInsecure 具有比客户端 HTTPSInsecure 更高的优先级
+// 如果不设置任何 HTTPSInsecure,则默认 HTTPSInsecure 为 false
+
+// 设置请求 HTTPSInsecure (只影响当前)
+request.SetHTTPSInsecure(true)                           // 设置请求 HTTPSInsecure 为 true
+isInsecure := request.GetHTTPSInsecure()                 // 获取请求 HTTPSInsecure
+
+// 设置客户端 HTTPSInsecure (用于客户端发送的所有请求)。
+client.SetHTTPSInsecure(true)                         // 设置客户端 HTTPSInsecure 为 true
+isInsecure := client.GetHTTPSInsecure()               // 获取客户端 HTTPSInsecure
+```
+
 ## Keep-alive
-阿里云 Go SDK 底层使用 Go 语言原生的 `net/http` 收发请求,因此配置方式与 `net/http`相同,您可以通过 config 直接将配置传递给底层的 httpClient
+阿里云 Go SDK 底层使用 Go 语言原生的 `net/http` 收发请求,因此配置方式与 `net/http` 相同,您可以通过 config 直接将配置传递给底层的 httpClient
 
 ```go
 httpTransport := http.Transport{

+ 30 - 0
sdk/client.go

@@ -16,6 +16,7 @@ package sdk
 
 import (
 	"context"
+	"crypto/tls"
 	"fmt"
 	"net"
 	"net/http"
@@ -53,6 +54,7 @@ var hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *
 
 // Client the type Client
 type Client struct {
+	isInsecure     bool
 	regionId       string
 	config         *Config
 	userAgent      map[string]string
@@ -72,6 +74,14 @@ func (client *Client) Init() (err error) {
 	panic("not support yet")
 }
 
+func (client *Client) SetHTTPSInsecure(isInsecure bool) {
+	client.isInsecure = isInsecure
+}
+
+func (client *Client) GetHTTPSInsecure() bool {
+	return client.isInsecure
+}
+
 func (client *Client) InitWithOptions(regionId string, config *Config, credential auth.Credential) (err error) {
 	client.isRunning = true
 	client.asyncChanLock = new(sync.RWMutex)
@@ -330,6 +340,7 @@ func Timeout(connectTimeout, readTimeout time.Duration) func(cxt context.Context
 		return conn, err
 	}
 }
+
 func (client *Client) setTimeout(request requests.AcsRequest) {
 	readTimeout, connectTimeout := client.getTimeout(request)
 	if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
@@ -341,6 +352,16 @@ func (client *Client) setTimeout(request requests.AcsRequest) {
 		}
 	}
 }
+
+func (client *Client) getHTTPSInsecure(request requests.AcsRequest) (insecure bool) {
+	if request.GetHTTPSInsecure() != nil {
+		insecure = *request.GetHTTPSInsecure()
+	} else {
+		insecure = client.GetHTTPSInsecure()
+	}
+	return insecure
+}
+
 func (client *Client) DoActionWithSigner(request requests.AcsRequest, response responses.AcsResponse, signer auth.Signer) (err error) {
 	httpRequest, err := client.buildRequestWithSigner(request, signer)
 	if err != nil {
@@ -348,6 +369,15 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 	}
 	client.setTimeout(request)
 
+	// Set whether to ignore certificate validation.
+	// Default InsecureSkipVerify is false.
+	if trans, ok := client.httpClient.Transport.(*http.Transport); ok && trans != nil {
+		trans.TLSClientConfig = &tls.Config{
+			InsecureSkipVerify: client.getHTTPSInsecure(request),
+		}
+		client.httpClient.Transport = trans
+	}
+
 	var httpResponse *http.Response
 	for retryTimes := 0; retryTimes <= client.config.MaxRetryTime; retryTimes++ {
 		debug("> %s %s %s", httpRequest.Method, httpRequest.URL.RequestURI(), httpRequest.Proto)

+ 28 - 0
sdk/client_test.go

@@ -18,6 +18,7 @@ import (
 	"bytes"
 	"io/ioutil"
 	"net/http"
+	"os"
 	"strconv"
 	"testing"
 	"time"
@@ -161,6 +162,33 @@ func Test_DoAction(t *testing.T) {
 	assert.Equal(t, false, client.isRunning)
 }
 
+func Test_DoAction_HTTPSInsecure(t *testing.T) {
+	client, err := NewClientWithAccessKey("regionid", "acesskeyid", "accesskeysecret")
+	assert.Nil(t, err)
+	assert.NotNil(t, client)
+
+	client.SetHTTPSInsecure(true)
+	request := requests.NewCommonRequest()
+	request.Product = "Ram"
+	request.Version = "2015-05-01"
+	request.SetScheme("HTTPS")
+	request.ApiName = "CreateRole"
+	request.QueryParams["RegionId"] = os.Getenv("REGION_ID")
+	request.TransToAcsRequest()
+	response := responses.NewCommonResponse()
+	err = client.DoAction(request, response)
+	assert.NotNil(t, err)
+	assert.Contains(t, err.Error(), "Specified access key is not found.")
+	trans := client.httpClient.Transport.(*http.Transport)
+	assert.Equal(t, true, trans.TLSClientConfig.InsecureSkipVerify)
+
+	request.SetHTTPSInsecure(false)
+	err = client.DoAction(request, response)
+	assert.NotNil(t, err)
+	trans = client.httpClient.Transport.(*http.Transport)
+	assert.Equal(t, false, trans.TLSClientConfig.InsecureSkipVerify)
+}
+
 func Test_DoAction_Timeout(t *testing.T) {
 	client, err := NewClientWithAccessKey("regionid", "acesskeyid", "accesskeysecret")
 	assert.Nil(t, err)

+ 11 - 0
sdk/requests/acs_request.go

@@ -77,6 +77,8 @@ type AcsRequest interface {
 	GetConnectTimeout() time.Duration
 	SetReadTimeout(readTimeout time.Duration)
 	SetConnectTimeout(connectTimeout time.Duration)
+	SetHTTPSInsecure(isInsecure bool)
+	GetHTTPSInsecure() *bool
 
 	GetUserAgent() map[string]string
 
@@ -104,6 +106,7 @@ type baseRequest struct {
 	RegionId       string
 	ReadTimeout    time.Duration
 	ConnectTimeout time.Duration
+	isInsecure     *bool
 
 	userAgent map[string]string
 	product   string
@@ -150,6 +153,14 @@ func (request *baseRequest) SetConnectTimeout(connectTimeout time.Duration) {
 	request.ConnectTimeout = connectTimeout
 }
 
+func (request *baseRequest) GetHTTPSInsecure() *bool {
+	return request.isInsecure
+}
+
+func (request *baseRequest) SetHTTPSInsecure(isInsecure bool) {
+	request.isInsecure = &isInsecure
+}
+
 func (request *baseRequest) GetContent() []byte {
 	return request.Content
 }

+ 5 - 0
sdk/requests/acs_request_test.go

@@ -97,6 +97,11 @@ func Test_AcsRequest(t *testing.T) {
 	r.SetConnectTimeout(5 * time.Second)
 	assert.Equal(t, 5*time.Second, r.GetConnectTimeout())
 
+	// GetHTTPSInsecure
+	assert.True(t, r.GetHTTPSInsecure() == nil)
+	r.SetHTTPSInsecure(true)
+	assert.Equal(t, true, *r.GetHTTPSInsecure())
+
 	// GetPort
 	assert.Equal(t, "", r.GetPort())