Compare commits

..

18 Commits

Author SHA1 Message Date
yndu13 185150a903 feat: support opentracing 2023-10-20 11:48:46 +08:00
nanhe 2b0e131d00 docs: update comments 2023-06-28 17:46:15 +08:00
nanhe e3922d2afb improve tls client config 2023-06-28 17:31:08 +08:00
dependabot[bot] 5ef2fcc54f Bump golang.org/x/net from 0.10.0 to 0.11.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.10.0 to 0.11.0.
- [Commits](https://github.com/golang/net/compare/v0.10.0...v0.11.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-27 23:13:13 +08:00
Jackson Tian 121efa4413 update actions setup-go to v4 2023-05-15 15:40:51 +08:00
dependabot[bot] aa99f50b3f Bump golang.org/x/net from 0.9.0 to 0.10.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.9.0 to 0.10.0.
- [Commits](https://github.com/golang/net/compare/v0.9.0...v0.10.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-15 15:36:25 +08:00
王理想 cb3a42bc23 judge maxidleconns int(0) pointer 2023-05-08 16:52:58 +08:00
王理想 712238a5c4 remove keep alive default 2023-05-08 16:52:58 +08:00
王理想 07ca3b69ad deal with MaxIdleConns, MaxIdleConnsPerHost, TLSHandshakeTimeout, and KeepAlive 2023-05-08 16:52:58 +08:00
dependabot[bot] e158cc5dc5 Bump golang.org/x/net from 0.0.0-20200226121028-0de0cce0169b to 0.9.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200226121028-0de0cce0169b to 0.9.0.
- [Release notes](https://github.com/golang/net/releases)
- [Commits](https://github.com/golang/net/commits/v0.9.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-26 11:32:33 +08:00
dependabot[bot] b46b464236 Bump github.com/json-iterator/go from 1.1.10 to 1.1.12
Bumps [github.com/json-iterator/go](https://github.com/json-iterator/go) from 1.1.10 to 1.1.12.
- [Release notes](https://github.com/json-iterator/go/releases)
- [Commits](https://github.com/json-iterator/go/compare/v1.1.10...v1.1.12)

---
updated-dependencies:
- dependency-name: github.com/json-iterator/go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-26 11:29:32 +08:00
Jackson Tian 636d89faa7 Create dependabot.yml 2023-04-26 11:27:59 +08:00
Jackson Tian c4f78703d7 Update README-CN.md 2023-04-26 11:21:46 +08:00
Jackson Tian 8a7c8512f8 Update README.md 2023-04-26 11:21:33 +08:00
Jackson Tian 02f393be3f Delete .travis.yml 2023-03-23 15:12:14 +08:00
nanhe c87ce79386 support port for url request 2023-03-23 15:01:26 +08:00
nanhe b9ace42a5b feat: return description and accessDeniedDetail in error info 2022-10-20 15:56:55 +08:00
nanhe 3a75a83be1 support when statusCode is *int 2022-06-20 20:19:19 +08:00
8 changed files with 185 additions and 78 deletions
+11
View File
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
+2 -2
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
@@ -32,4 +32,4 @@ jobs:
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./tea/... ./utils/...
- name: CodeCov
run: bash <(curl -s https://codecov.io/bash)
run: bash <(curl -s https://codecov.io/bash)
-24
View File
@@ -1,24 +0,0 @@
language: go
go:
- 1.12.x
branches: # build only on these branches
only:
- master
install:
- export GO111MODULE=on
notifications:
webhooks: https://oapi.dingtalk.com/robot/send?access_token=096ed387df243a6d60835aadeccc47165f3813bc7cb81cdd0cfeadfd28e3acc1
email: false
on_success: change
on_failure: always
script:
- go mod tidy
- go test -race -coverprofile=coverage.txt -covermode=atomic ./tea/... ./utils/...
after_success:
- bash <(curl -s https://codecov.io/bash)
+3 -3
View File
@@ -2,11 +2,11 @@
<a href="https://badge.fury.io/gh/alibabacloud-go%2Ftea"><img src="https://badge.fury.io/gh/alibabacloud-go%2Ftea.svg" alt="Latest Stable Version"></a>
<a href="https://codecov.io/gh/alibabacloud-go/tea"><img src="https://codecov.io/gh/alibabacloud-go/tea/branch/master/graph/badge.svg" alt="codecov"></a>
<a href="https://travis-ci.org/alibabacloud-go/tea"><img src="https://travis-ci.org/alibabacloud-go/tea.svg?branch=master" alt="Travis Build Status"></a>
[![Go CI](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml/badge.svg)](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml)
该项目用于支持TEA OpenAPI DSL。它是http请求的底层库.
该项目用于支持 Darabonba OpenAPI DSL。它是http请求的底层库.
## 许可证
[Apache-2.0](/LICENSE)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
+3 -3
View File
@@ -2,11 +2,11 @@
<a href="https://badge.fury.io/gh/alibabacloud-go%2Ftea"><img src="https://badge.fury.io/gh/alibabacloud-go%2Ftea.svg" alt="Latest Stable Version"></a>
<a href="https://codecov.io/gh/alibabacloud-go/tea"><img src="https://codecov.io/gh/alibabacloud-go/tea/branch/master/graph/badge.svg" alt="codecov"></a>
<a href="https://travis-ci.org/alibabacloud-go/tea"><img src="https://travis-ci.org/alibabacloud-go/tea.svg?branch=master" alt="Travis Build Status"></a>
[![Go CI](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml/badge.svg)](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml)
This project is used for support TEA OpenAPI DSL. It's a low-level library for http request.
This project is used for support Darabonba OpenAPI DSL. It's a low-level library for http request.
## License
[Apache-2.0](/LICENSE)
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
+4 -3
View File
@@ -4,7 +4,8 @@ go 1.14
require (
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68
github.com/json-iterator/go v1.1.10
github.com/modern-go/reflect2 v1.0.1
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
github.com/json-iterator/go v1.1.12
github.com/modern-go/reflect2 v1.0.2
golang.org/x/net v0.11.0
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b
)
+89 -29
View File
@@ -26,6 +26,8 @@ import (
"github.com/alibabacloud-go/debug/debug"
"github.com/alibabacloud-go/tea/utils"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"golang.org/x/net/proxy"
)
@@ -69,12 +71,14 @@ type Response struct {
// SDKError struct is used save error code and message
type SDKError struct {
Code *string
StatusCode *int
Message *string
Data *string
Stack *string
errMsg *string
Code *string
StatusCode *int
Message *string
Data *string
Stack *string
errMsg *string
Description *string
AccessDeniedDetail map[string]interface{}
}
// RuntimeObject is used for converting http configuration
@@ -95,6 +99,8 @@ type RuntimeObject struct {
Listener utils.ProgressListener `json:"listener" xml:"listener"`
Tracker *utils.ReaderTracker `json:"tracker" xml:"tracker"`
Logger *utils.Logger `json:"logger" xml:"logger"`
Span *opentracing.Span `json:"span" xml:"span"`
IsCloseTrace *bool `json:"isCloseTrace" xml:"isCloseTrace"`
}
type teaClient struct {
@@ -131,6 +137,7 @@ func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject {
Key: TransInterfaceToString(runtime["key"]),
Cert: TransInterfaceToString(runtime["cert"]),
CA: TransInterfaceToString(runtime["ca"]),
IsCloseTrace: TransInterfaceToBool(runtime["isCloseTrace"]),
}
if runtime["listener"] != nil {
runtimeObject.Listener = runtime["listener"].(utils.ProgressListener)
@@ -141,6 +148,9 @@ func NewRuntimeObject(runtime map[string]interface{}) *RuntimeObject {
if runtime["logger"] != nil {
runtimeObject.Logger = runtime["logger"].(*utils.Logger)
}
if runtime["span"] != nil {
runtimeObject.Span = runtime["span"].(*opentracing.Span)
}
return runtimeObject
}
@@ -181,6 +191,20 @@ func NewSDKError(obj map[string]interface{}) *SDKError {
if obj["message"] != nil {
err.Message = String(obj["message"].(string))
}
if obj["description"] != nil {
err.Description = String(obj["description"].(string))
}
if detail := obj["accessDeniedDetail"]; detail != nil {
r := reflect.ValueOf(detail)
if r.Kind().String() == "map" {
res := make(map[string]interface{})
tmp := r.MapKeys()
for _, key := range tmp {
res[key.String()] = r.MapIndex(key).Interface()
}
err.AccessDeniedDetail = res
}
}
if data := obj["data"]; data != nil {
r := reflect.ValueOf(data)
if r.Kind().String() == "map" {
@@ -197,6 +221,8 @@ func NewSDKError(obj map[string]interface{}) *SDKError {
if err_ == nil {
err.StatusCode = Int(code)
}
} else if code, ok := statusCode.(*int); ok {
err.StatusCode = code
}
}
}
@@ -244,7 +270,7 @@ func Convert(in interface{}, out interface{}) error {
return err
}
// Convert is use convert map[string]interface object to struct
// Recover is used to format error
func Recover(in interface{}) error {
if in == nil {
return nil
@@ -304,6 +330,9 @@ func DoRequest(request *Request, requestRuntime map[string]interface{}) (respons
requestURL := ""
request.Domain = request.Headers["host"]
if request.Port != nil {
request.Domain = String(fmt.Sprintf("%s:%d", StringValue(request.Domain), IntValue(request.Port)))
}
requestURL = fmt.Sprintf("%s://%s%s", StringValue(request.Protocol), StringValue(request.Domain), StringValue(request.Pathname))
queryParams := request.Query
// sort QueryParams by key
@@ -357,6 +386,31 @@ func DoRequest(request *Request, requestRuntime map[string]interface{}) (respons
event := utils.NewProgressEvent(utils.TransferStartedEvent, 0, int64(contentlength), 0)
utils.PublishProgress(runtimeObject.Listener, event)
// Set tracer
var span opentracing.Span
if ok := opentracing.IsGlobalTracerRegistered(); ok && BoolValue(runtimeObject.IsCloseTrace) != true {
tracer := opentracing.GlobalTracer()
var rootCtx opentracing.SpanContext
var rootSpan opentracing.Span
if runtimeObject.Span != nil {
rootSpan = *runtimeObject.Span
rootCtx = rootSpan.Context()
}
span = tracer.StartSpan(
httpRequest.URL.RequestURI(),
opentracing.ChildOf(rootCtx),
opentracing.Tag{Key: string(ext.Component), Value: "aliyunApi"},
opentracing.Tag{Key: "request", Value: requestURL})
defer span.Finish()
tracer.Inject(
span.Context(),
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(httpRequest.Header))
}
putMsgToMap(fieldMap, httpRequest)
startTime := time.Now()
fieldMap["{start_time}"] = startTime.Format("2006-01-02 15:04:05")
@@ -394,28 +448,30 @@ func getHttpTransport(req *Request, runtime *RuntimeObject) (*http.Transport, er
if err != nil {
return nil, err
}
if strings.ToLower(*req.Protocol) == "https" &&
runtime.Key != nil && runtime.Cert != nil {
cert, err := tls.X509KeyPair([]byte(StringValue(runtime.Cert)), []byte(StringValue(runtime.Key)))
if err != nil {
return nil, err
}
trans.TLSClientConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
InsecureSkipVerify: BoolValue(runtime.IgnoreSSL),
}
if runtime.CA != nil {
clientCertPool := x509.NewCertPool()
ok := clientCertPool.AppendCertsFromPEM([]byte(StringValue(runtime.CA)))
if !ok {
return nil, errors.New("Failed to parse root certificate")
if strings.ToLower(*req.Protocol) == "https" {
if BoolValue(runtime.IgnoreSSL) != true {
trans.TLSClientConfig = &tls.Config{
InsecureSkipVerify: false,
}
if runtime.Key != nil && runtime.Cert != nil && StringValue(runtime.Key) != "" && StringValue(runtime.Cert) != "" {
cert, err := tls.X509KeyPair([]byte(StringValue(runtime.Cert)), []byte(StringValue(runtime.Key)))
if err != nil {
return nil, err
}
trans.TLSClientConfig.Certificates = []tls.Certificate{cert}
}
if runtime.CA != nil && StringValue(runtime.CA) != "" {
clientCertPool := x509.NewCertPool()
ok := clientCertPool.AppendCertsFromPEM([]byte(StringValue(runtime.CA)))
if !ok {
return nil, errors.New("Failed to parse root certificate")
}
trans.TLSClientConfig.RootCAs = clientCertPool
}
} else {
trans.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
trans.TLSClientConfig.RootCAs = clientCertPool
}
} else {
trans.TLSClientConfig = &tls.Config{
InsecureSkipVerify: BoolValue(runtime.IgnoreSSL),
}
}
if httpProxy != nil {
@@ -455,6 +511,10 @@ func getHttpTransport(req *Request, runtime *RuntimeObject) (*http.Transport, er
} else {
trans.DialContext = setDialContext(runtime)
}
if runtime.MaxIdleConns != nil && *runtime.MaxIdleConns > 0 {
trans.MaxIdleConns = IntValue(runtime.MaxIdleConns)
trans.MaxIdleConnsPerHost = IntValue(runtime.MaxIdleConns)
}
return trans, nil
}
@@ -957,7 +1017,7 @@ func validatePtr(field reflect.StructField, elementValue reflect.Value, contains
}
}
}
} else {
} else if elementValue.Elem().Type().Kind() == reflect.Struct {
err := validate(elementValue)
if err != nil {
return err
+73 -14
View File
@@ -16,6 +16,8 @@ import (
"time"
"github.com/alibabacloud-go/tea/utils"
opentracing "github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
)
type test struct {
@@ -47,18 +49,19 @@ var runtimeObj = map[string]interface{}{
}
type validateTest struct {
Num1 *int `json:"num1,omitempty" require:"true" minimum:"2"`
Num2 *int `json:"num2,omitempty" maximum:"6"`
Name1 *string `json:"name1,omitempty" maxLength:"4"`
Name2 *string `json:"name2,omitempty" minLength:"2"`
Str *string `json:"str,omitempty" pattern:"[a-d]*" maxLength:"4"`
MaxLength *errMaxLength `json:"MaxLength,omitempty"`
MinLength *errMinLength `json:"MinLength,omitempty"`
Maximum *errMaximum `json:"Maximum,omitempty"`
Minimum *errMinimum `json:"Minimum,omitempty"`
MaxItems *errMaxItems `json:"MaxItems,omitempty"`
MinItems *errMinItems `json:"MinItems,omitempty"`
List []*string `json:"list,omitempty" pattern:"[a-d]*" minItems:"2" maxItems:"3" maxLength:"4"`
Num1 *int `json:"num1,omitempty" require:"true" minimum:"2"`
Num2 *int `json:"num2,omitempty" maximum:"6"`
Name1 *string `json:"name1,omitempty" maxLength:"4"`
Name2 *string `json:"name2,omitempty" minLength:"2"`
Str *string `json:"str,omitempty" pattern:"[a-d]*" maxLength:"4"`
MaxLength *errMaxLength `json:"MaxLength,omitempty"`
MinLength *errMinLength `json:"MinLength,omitempty"`
Maximum *errMaximum `json:"Maximum,omitempty"`
Minimum *errMinimum `json:"Minimum,omitempty"`
MaxItems *errMaxItems `json:"MaxItems,omitempty"`
MinItems *errMinItems `json:"MinItems,omitempty"`
List []*string `json:"list,omitempty" pattern:"[a-d]*" minItems:"2" maxItems:"3" maxLength:"4"`
PtrNotStruct *opentracing.Span `json:"span" xml:"span"`
}
type errMaxLength struct {
@@ -169,6 +172,14 @@ func TestSDKError(t *testing.T) {
"requestId": "dfadfa32cgfdcasd4313",
"hostId": "github.com/alibabacloud/tea",
},
"description": "description",
"accessDeniedDetail": map[string]interface{}{
"AuthAction": "ram:ListUsers",
"AuthPrincipalType": "SubUser",
"PolicyType": "ResourceGroupLevelIdentityBassdPolicy",
"NoPermissionType": "ImplicitDeny",
"UserId": 123,
},
})
utils.AssertNotNil(t, err)
utils.AssertEqual(t, "SDKError:\n StatusCode: 404\n Code: code\n Message: message\n Data: {\"hostId\":\"github.com/alibabacloud/tea\",\"httpCode\":\"404\",\"requestId\":\"dfadfa32cgfdcasd4313\"}\n", err.Error())
@@ -176,6 +187,9 @@ func TestSDKError(t *testing.T) {
err.SetErrMsg("test")
utils.AssertEqual(t, "test", err.Error())
utils.AssertEqual(t, 404, *err.StatusCode)
utils.AssertEqual(t, "description", *err.Description)
utils.AssertEqual(t, "ImplicitDeny", err.AccessDeniedDetail["NoPermissionType"])
utils.AssertEqual(t, 123, err.AccessDeniedDetail["UserId"])
err = NewSDKError(map[string]interface{}{
"statusCode": "404",
@@ -194,6 +208,14 @@ func TestSDKError(t *testing.T) {
utils.AssertNotNil(t, err)
utils.AssertEqual(t, 500, *err.StatusCode)
err = NewSDKError(map[string]interface{}{
"data": map[string]interface{}{
"statusCode": Int(500),
},
})
utils.AssertNotNil(t, err)
utils.AssertEqual(t, 500, *err.StatusCode)
err = NewSDKError(map[string]interface{}{
"data": map[string]interface{}{
"statusCode": "500",
@@ -523,20 +545,32 @@ func Test_DoRequest(t *testing.T) {
runtimeObj["key"] = "private rsa key"
runtimeObj["cert"] = "private certification"
runtimeObj["ca"] = "private ca"
runtimeObj["ignoreSSL"] = true
resp, err = DoRequest(request, runtimeObj)
utils.AssertNil(t, err)
utils.AssertNotNil(t, resp)
// update the host is to restart a client
request.Headers["host"] = String("a.com")
runtimeObj["ignoreSSL"] = false
resp, err = DoRequest(request, runtimeObj)
utils.AssertNotNil(t, err)
utils.AssertEqual(t, "tls: failed to find any PEM data in certificate input", err.Error())
utils.AssertNil(t, resp)
// update the host is to restart a client
request.Headers["host"] = String("b.com")
runtimeObj["key"] = key
runtimeObj["cert"] = cert
runtimeObj["ca"] = "private ca"
runtimeObj["socks5Proxy"] = "socks5://someuser:somepassword@cs.aliyun.com"
_, err = DoRequest(request, runtimeObj)
utils.AssertNotNil(t, err)
utils.AssertEqual(t, "Failed to parse root certificate", err.Error())
// update the host is to restart a client
request.Headers["host"] = String("c.com")
runtimeObj["ca"] = ca
runtimeObj["socks5Proxy"] = "socks5://someuser:somepassword@cs.aliyuncs.com"
resp, err = DoRequest(request, runtimeObj)
utils.AssertNil(t, err)
utils.AssertEqual(t, "test", StringValue(resp.Headers["tea"]))
@@ -546,6 +580,20 @@ func Test_DoRequest(t *testing.T) {
resp, err = DoRequest(request, runtimeObj)
utils.AssertNil(t, err)
utils.AssertEqual(t, "test", StringValue(resp.Headers["tea"]))
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) {
utils.AssertEqual(t, "tea-cn-hangzhou.aliyuncs.com:1080", req.Host)
return mockResponse(200, ``, errors.New("Internal error"))
}
}
request.Pathname = String("/log")
request.Protocol = String("http")
request.Port = Int(1080)
request.Headers["host"] = String("tea-cn-hangzhou.aliyuncs.com")
resp, err = DoRequest(request, runtimeObj)
utils.AssertNil(t, resp)
utils.AssertEqual(t, `Internal error`, err.Error())
}
func Test_DoRequestWithConcurrent(t *testing.T) {
@@ -703,6 +751,17 @@ func Test_Validate(t *testing.T) {
err := Validate(config)
utils.AssertNil(t, err)
tracer := opentracing.GlobalTracer()
span := tracer.StartSpan(
"aliyuncs.com/test",
opentracing.Tag{Key: string(ext.Component), Value: "aliyunApi"},
opentracing.Tag{Key: "request", Value: "test"})
config = &validateTest{
PtrNotStruct: &span,
}
err = Validate(config)
utils.AssertNil(t, err)
err = Validate(new(validateTest))
utils.AssertEqual(t, err.Error(), "num1 should be setted")