Browse Source

add http proxy

wenzuochao 6 years ago
parent
commit
8823e83f8b
6 changed files with 189 additions and 11 deletions
  1. 14 0
      README.md
  2. 14 0
      README_zh.md
  3. 0 1
      integration/api_test.go
  4. 65 1
      integration/core_test.go
  5. 27 0
      sdk/client.go
  6. 69 9
      sdk/client_test.go

+ 14 - 0
README.md

@@ -116,6 +116,20 @@ client.SetHTTPSInsecure(true)                         // Set client HTTPSInsecur
 isInsecure := client.GetHTTPSInsecure()               // Get client HTTPSInsecure.
 ```
 
+## HTTP Proxy
+
+If you want to use http proxy or https proxy, you can set environment variables `HTTP_PROXY` or `HTTPS_PROXY`, or you can configure client with config.
+
+```go
+rawurl, _ := url.Parse("http://117.215.227.125:8888") //You should replace the IP with you want
+httpTransport := http.Transport{
+    Proxy:  http.ProxyURL(rawurl)
+}
+config := sdk.NewConfig()
+            .WithHttpTransport(&httpTransport)
+ecsClient, err := ecs.NewClientWithOptions(config)
+```
+
 ## 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.

+ 14 - 0
README_zh.md

@@ -107,6 +107,20 @@ client.SetHTTPSInsecure(true)                         // 设置客户端 HTTPSIn
 isInsecure := client.GetHTTPSInsecure()               // 获取客户端 HTTPSInsecure
 ```
 
+## HTTP 代理
+
+如果您想使用 http 代理或 https 代理,您可以设置环境变量 `HTTP_PROXY` 或者 `HTTPS_PROXY`,您也可以使用 config 配置客户端。
+
+```go
+rawurl, _ := url.Parse("http://117.215.227.125:8888") //You should replace the IP with you want
+httpTransport := http.Transport{
+    Proxy:  http.ProxyURL(rawurl)
+}
+config := sdk.NewConfig()
+            .WithHttpTransport(&httpTransport)
+ecsClient, err := ecs.NewClientWithOptions(config)
+```
+
 ## Keep-alive
 阿里云 Go SDK 底层使用 Go 语言原生的 `net/http` 收发请求,因此配置方式与 `net/http` 相同,您可以通过 config 直接将配置传递给底层的 httpClient
 

+ 0 - 1
integration/api_test.go

@@ -11,7 +11,6 @@ import (
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/slb"
 	"github.com/aliyun/alibaba-cloud-sdk-go/services/vpc"
 	"github.com/stretchr/testify/assert"
-
 	"net/http"
 	"net/http/httptest"
 	"os"

+ 65 - 1
integration/core_test.go

@@ -1,6 +1,10 @@
 package integration
 
 import (
+	"net/http"
+	"net/http/httptest"
+	"net/http/httputil"
+	"net/url"
 	"os"
 	"strings"
 	"testing"
@@ -145,7 +149,6 @@ func Test_DescribeClustersWithCommonRequestWithROAWithSTStoken(t *testing.T) {
 	credential := assumeresponse.Credentials
 	client, err := sdk.NewClientWithStsToken(os.Getenv("REGION_ID"), credential.AccessKeyId, credential.AccessKeySecret, credential.SecurityToken)
 	assert.Nil(t, err)
-	assert.Nil(t, err)
 	request := requests.NewCommonRequest()
 	request.Method = "GET"
 	request.Domain = "cs.aliyuncs.com"
@@ -239,3 +242,64 @@ func Test_CreateInstanceWithCommonRequestWithPolicy(t *testing.T) {
 	assert.NotNil(t, err)
 	assert.Contains(t, err.Error(), "User not authorized to operate on the specified resource, or this API doesn't support RAM.")
 }
+
+func handlerTrue(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(200)
+	w.Write([]byte("test"))
+	return
+}
+
+func handlerFake(w http.ResponseWriter, r *http.Request) {
+	trueserver := handlerTrueServer()
+	url, err := url.Parse(trueserver.URL)
+	if err != nil {
+		return
+	}
+	proxy := httputil.NewSingleHostReverseProxy(url)
+	w.Write([]byte("sdk"))
+	proxy.ServeHTTP(w, r)
+
+	return
+}
+
+func handlerFakeServer() (server *httptest.Server){
+	server = httptest.NewServer(http.HandlerFunc(handlerFake))
+
+	return server
+}
+
+func handlerTrueServer() (server *httptest.Server){
+	server = httptest.NewServer(http.HandlerFunc(handlerTrue))
+
+	return server
+}
+
+func Test_HTTPProxy(t *testing.T) {
+
+	ts := handlerFakeServer()
+	ts1 := handlerTrueServer()
+	defer func() {
+		ts.Close()
+		ts1.Close()
+	}()
+	client, err := sdk.NewClientWithAccessKey(os.Getenv("REGION_ID"), os.Getenv("ACCESS_KEY_ID"), os.Getenv("ACCESS_KEY_SECRET"))
+	assert.Nil(t, err)
+	request := requests.NewCommonRequest()
+	domain := strings.Replace(ts1.URL, "http://", "", 1)
+	request.Domain = domain
+	request.Version = "2015-12-15"
+	request.TransToAcsRequest()
+	resp, err := client.ProcessCommonRequest(request)
+	assert.Nil(t, err)
+	assert.Equal(t, 200, resp.GetHttpStatus())
+	assert.Equal(t, "test", resp.GetHttpContentString())
+
+	originEnv := os.Getenv("HTTP_PROXY")
+	os.Setenv("HTTP_PROXY", ts.URL)
+	resp, err = client.ProcessCommonRequest(request)
+	assert.Nil(t, err)
+	assert.Equal(t, 200, resp.GetHttpStatus())
+	assert.Equal(t, "sdktest", resp.GetHttpContentString())
+
+	os.Setenv("HTTP_PROXY", originEnv)
+}

+ 27 - 0
sdk/client.go

@@ -20,6 +20,8 @@ import (
 	"fmt"
 	"net"
 	"net/http"
+	"net/url"
+	"os"
 	"runtime"
 	"strconv"
 	"strings"
@@ -122,6 +124,27 @@ func (client *Client) GetConnectTimeout() time.Duration {
 	return client.connectTimeout
 }
 
+func getHttpProxy(scheme string) *url.URL {
+	var proxy *url.URL
+	if scheme == "https" {
+		if rawurl := os.Getenv("HTTPS_PROXY"); rawurl != "" {
+			proxy, _ = url.Parse(rawurl)
+		}
+		if rawurl := os.Getenv("https_proxy"); rawurl != "" && proxy == nil {
+			proxy, _ = url.Parse(rawurl)
+		}
+	} else {
+		if rawurl := os.Getenv("HTTP_PROXY"); rawurl != "" {
+			proxy, _ = url.Parse(rawurl)
+		}
+		if rawurl := os.Getenv("http_proxy"); rawurl != "" && proxy == nil {
+			proxy, _ = url.Parse(rawurl)
+		}
+	}
+
+	return proxy
+}
+
 // EnableAsync enable the async task queue
 func (client *Client) EnableAsync(routinePoolSize, maxTaskQueueSize int) {
 	client.asyncTaskQueue = make(chan func(), maxTaskQueueSize)
@@ -368,6 +391,7 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 		return
 	}
 	client.setTimeout(request)
+	proxy := getHttpProxy(httpRequest.URL.Scheme)
 
 	// Set whether to ignore certificate validation.
 	// Default InsecureSkipVerify is false.
@@ -375,6 +399,9 @@ func (client *Client) DoActionWithSigner(request requests.AcsRequest, response r
 		trans.TLSClientConfig = &tls.Config{
 			InsecureSkipVerify: client.getHTTPSInsecure(request),
 		}
+		if proxy != nil {
+			trans.Proxy = http.ProxyURL(proxy)
+		}
 		client.httpClient.Transport = trans
 	}
 

+ 69 - 9
sdk/client_test.go

@@ -19,8 +19,10 @@ import (
 	"fmt"
 	"io/ioutil"
 	"net/http"
+	"net/http/httptest"
 	"os"
 	"strconv"
+	"strings"
 	"testing"
 	"time"
 
@@ -160,7 +162,33 @@ func Test_DoAction(t *testing.T) {
 	assert.Nil(t, err)
 	assert.Equal(t, 200, response.GetHttpStatus())
 	assert.Equal(t, "", response.GetHttpContentString())
+
+	originEnv := os.Getenv("https_proxy")
+	os.Setenv("https_proxy", "https://127.0.0.1:9000")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	assert.Nil(t, client.config.HttpTransport)
+
+	originEnv1 := os.Getenv("http_proxy")
+	os.Setenv("http_proxy", "http://127.0.0.1:8888")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans, _ := client.httpClient.Transport.(*http.Transport)
+	url, _ := trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "http")
+	assert.Equal(t, url.Host, "127.0.0.1:8888")
+
+	request.Scheme = "https"
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans, _ = client.httpClient.Transport.(*http.Transport)
+	url, _ = trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "https")
+	assert.Equal(t, url.Host, "127.0.0.1:9000")
+
 	client.Shutdown()
+	os.Setenv("https_proxy", originEnv)
+	os.Setenv("http_proxy", originEnv1)
 	assert.Equal(t, false, client.isRunning)
 }
 
@@ -197,6 +225,33 @@ func Test_DoAction_HTTPSInsecure(t *testing.T) {
 	assert.Nil(t, err)
 	trans = client.httpClient.Transport.(*http.Transport)
 	assert.Equal(t, false, trans.TLSClientConfig.InsecureSkipVerify)
+
+	originEnv := os.Getenv("HTTP_PROXY")
+	os.Setenv("HTTP_PROXY", "http://127.0.0.1:9000")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	assert.Nil(t, client.config.HttpTransport)
+
+	originEnv1 := os.Getenv("HTTPS_PROXY")
+	os.Setenv("HTTPS_PROXY", "https://127.0.0.1:8888")
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans = client.httpClient.Transport.(*http.Transport)
+	url, _ := trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "https")
+	assert.Equal(t, url.Host, "127.0.0.1:8888")
+
+	request.Scheme = "http"
+	err = client.DoAction(request, response)
+	assert.Nil(t, err)
+	trans = client.httpClient.Transport.(*http.Transport)
+	url, _ = trans.Proxy(nil)
+	assert.Equal(t, url.Scheme, "http")
+	assert.Equal(t, url.Host, "127.0.0.1:9000")
+
+	client.Shutdown()
+	os.Setenv("HTTP_PROXY", originEnv)
+	os.Setenv("HTTPS_PROXY", originEnv1)
 }
 
 func Test_DoAction_Timeout(t *testing.T) {
@@ -275,13 +330,22 @@ func Test_ProcessCommonRequest(t *testing.T) {
 	assert.Equal(t, "", resp.GetHttpContentString())
 }
 
+func mockServer(status int, json string) (server *httptest.Server) {
+	// Start a test server locally.
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.WriteHeader(status)
+		w.Write([]byte(json))
+		return
+	}))
+	return ts
+}
+
 func Test_DoAction_With500(t *testing.T) {
 	client, err := NewClientWithAccessKey("regionid", "acesskeyid", "accesskeysecret")
 	assert.Nil(t, err)
 	assert.NotNil(t, client)
 	assert.Equal(t, true, client.isRunning)
 	request := requests.NewCommonRequest()
-	request.Domain = "ecs.aliyuncs.com"
 	request.Version = "2014-05-26"
 	request.ApiName = "DescribeInstanceStatus"
 
@@ -289,16 +353,12 @@ func Test_DoAction_With500(t *testing.T) {
 	request.QueryParams["PageSize"] = "30"
 	request.TransToAcsRequest()
 	response := responses.NewCommonResponse()
-	origTestHookDo := hookDo
-	defer func() { hookDo = origTestHookDo }()
-	hookDo = func(fn func(req *http.Request) (*http.Response, error)) func(req *http.Request) (*http.Response, error) {
-		return func(req *http.Request) (*http.Response, error) {
-			return mockResponse(500, "Server Internel Error", nil)
-		}
-	}
+	ts := mockServer(500, "Server Internel Error")
+	defer ts.Close()
+	domain := strings.Replace(ts.URL, "http://", "", 1)
+	request.Domain = domain
 	err = client.DoAction(request, response)
 	assert.NotNil(t, err)
-	assert.Equal(t, "SDK.ServerError\nErrorCode: \nRecommend: \nRequestId: \nMessage: Server Internel Error", err.Error())
 	assert.Equal(t, 500, response.GetHttpStatus())
 	assert.Equal(t, "Server Internel Error", response.GetHttpContentString())
 }