vendor: update github.com/yunify/qingstor-sdk-go to v3

This commit is contained in:
Nick Craig-Wood
2019-08-14 16:15:34 +01:00
parent b84cc0cae7
commit a72ef7ca0e
51 changed files with 1560 additions and 750 deletions
-55
View File
@@ -1,55 +0,0 @@
sudo: required
services:
- docker
language: go
go:
- master
- 1.9
- 1.8
- 1.7
cache:
directories:
- ${HOME}/source
before_install:
- pushd ${HOME}/source
- if [[ ! -d "./make-4.0" ]]; then
wget http://ftp.gnu.org/gnu/make/make-4.0.tar.gz &&
tar -vxzf make-4.0.tar.gz &&
pushd make-4.0 && ./configure && make && popd;
fi
- pushd make-4.0 && sudo make install && popd
- if [[ ! -d "./glide-v0.12.3" ]]; then
wget https://github.com/Masterminds/glide/releases/download/v0.12.3/glide-v0.12.3-linux-amd64.tar.gz &&
tar -vxzf glide-v0.12.3-linux-amd64.tar.gz &&
mv linux-amd64 glide-v0.12.3;
fi
- pushd glide-v0.12.3 && sudo cp glide /usr/local/bin && popd
- if [[ ! -d "./snips-v0.2.8" ]]; then
wget https://github.com/yunify/snips/releases/download/v0.2.8/snips-v0.2.8-linux_amd64.tar.gz &&
mkdir snips-v0.2.8 &&
pushd snips-v0.2.8 &&
tar -vxzf ../snips-v0.2.8-linux_amd64.tar.gz &&
popd;
fi
- pushd snips-v0.2.8 && sudo cp snips /usr/local/bin && popd
- popd
- /usr/local/bin/make --version
- /usr/local/bin/glide --version
install:
- go get -u github.com/golang/lint/golint;
- glide install
- git submodule init
before_script:
- /usr/local/bin/make update
- /usr/local/bin/make generate
script:
- /usr/local/bin/make check
- /usr/local/bin/make release
- /usr/local/bin/make build test test-coverage
-1
View File
@@ -1 +0,0 @@
Jingwen Peng <pengsrc@yunify.com>
-32
View File
@@ -1,32 +0,0 @@
hash: 6e1d4e547cdd58944ef920192480d29edd118cac0e8269d793315066d1249b4e
updated: 2018-07-16T14:42:51.093308+08:00
imports:
- name: github.com/pengsrc/go-shared
version: db9bcfc423552eef790d989bb81ef055d0d26286
subpackages:
- buffer
- check
- convert
- log
- reopen
- name: gopkg.in/yaml.v2
version: 287cf08546ab5e7e37d55a84f7ed3fd1db036de5
repo: https://github.com/go-yaml/yaml.git
testImports:
- name: github.com/DATA-DOG/godog
version: 623ff9946e5c72834c19a019a153b8e3a338a52c
subpackages:
- colors
- gherkin
- name: github.com/davecgh/go-spew
version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9
subpackages:
- spew
- name: github.com/pmezard/go-difflib
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
subpackages:
- difflib
- name: github.com/stretchr/testify
version: 69483b4bd14f5845b5a1e55bca19e954e827f1d0
subpackages:
- assert
-11
View File
@@ -1,11 +0,0 @@
package: github.com/yunify/qingstor-sdk-go
import:
# YAML
- package: gopkg.in/yaml.v2
version: 287cf08546ab5e7e37d55a84f7ed3fd1db036de5
repo: https://github.com/go-yaml/yaml.git
# Shared packages
- package: github.com/pengsrc/go-shared
version: db9bcfc423552eef790d989bb81ef055d0d26286
-163
View File
@@ -1,163 +0,0 @@
// +-------------------------------------------------------------------------
// | Copyright (C) 2016 Yunify, Inc.
// +-------------------------------------------------------------------------
// | Licensed under the Apache License, Version 2.0 (the "License");
// | you may not use this work except in compliance with the License.
// | You may obtain a copy of the License in the LICENSE file, or at:
// |
// | http://www.apache.org/licenses/LICENSE-2.0
// |
// | Unless required by applicable law or agreed to in writing, software
// | distributed under the License is distributed on an "AS IS" BASIS,
// | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// | See the License for the specific language governing permissions and
// | limitations under the License.
// +-------------------------------------------------------------------------
package builder
import (
"bytes"
"crypto/md5"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"github.com/pengsrc/go-shared/convert"
"github.com/yunify/qingstor-sdk-go"
"github.com/yunify/qingstor-sdk-go/logger"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/utils"
)
// QingStorBuilder is the request builder for QingStor service.
type QingStorBuilder struct {
baseBuilder *BaseBuilder
}
// BuildHTTPRequest builds http request with an operation and an input.
func (qb *QingStorBuilder) BuildHTTPRequest(o *data.Operation, i *reflect.Value) (*http.Request, error) {
qb.baseBuilder = &BaseBuilder{}
qb.baseBuilder.operation = o
qb.baseBuilder.input = i
_, err := qb.baseBuilder.parse()
if err != nil {
return nil, err
}
err = qb.parseURL()
if err != nil {
return nil, err
}
httpRequest, err := http.NewRequest(qb.baseBuilder.operation.RequestMethod,
qb.baseBuilder.parsedURL, qb.baseBuilder.parsedBody)
if err != nil {
return nil, err
}
err = qb.baseBuilder.setupHeaders(httpRequest)
if err != nil {
return nil, err
}
err = qb.setupHeaders(httpRequest)
if err != nil {
return nil, err
}
logger.Infof(nil, fmt.Sprintf(
"Built QingStor request: [%d] %s",
convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822),
httpRequest.URL.String(),
))
logger.Infof(nil, fmt.Sprintf(
"QingStor request headers: [%d] %s",
convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822),
fmt.Sprint(httpRequest.Header),
))
if qb.baseBuilder.parsedBodyString != "" {
logger.Infof(nil, fmt.Sprintf(
"QingStor request body string: [%d] %s",
convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822),
qb.baseBuilder.parsedBodyString,
))
}
return httpRequest, nil
}
func (qb *QingStorBuilder) parseURL() error {
config := qb.baseBuilder.operation.Config
zone := (*qb.baseBuilder.parsedProperties)["zone"]
port := strconv.Itoa(config.Port)
endpoint := config.Protocol + "://" + config.Host + ":" + port
if zone != "" {
endpoint = config.Protocol + "://" + zone + "." + config.Host + ":" + port
}
requestURI := qb.baseBuilder.operation.RequestURI
for key, value := range *qb.baseBuilder.parsedProperties {
endpoint = strings.Replace(endpoint, "<"+key+">", utils.URLQueryEscape(value), -1)
requestURI = strings.Replace(requestURI, "<"+key+">", utils.URLQueryEscape(value), -1)
}
requestURI = regexp.MustCompile(`/+`).ReplaceAllString(requestURI, "/")
requestURL, err := url.Parse(endpoint + requestURI)
if err != nil {
return err
}
if qb.baseBuilder.parsedQuery != nil {
queryValue := requestURL.Query()
for key, value := range *qb.baseBuilder.parsedQuery {
queryValue.Set(key, value)
}
requestURL.RawQuery = queryValue.Encode()
}
qb.baseBuilder.parsedURL = requestURL.String()
return nil
}
func (qb *QingStorBuilder) setupHeaders(httpRequest *http.Request) error {
if httpRequest.Header.Get("User-Agent") == "" {
version := fmt.Sprintf(`Go v%s`, strings.Replace(runtime.Version(), "go", "", -1))
system := fmt.Sprintf(`%s_%s_%s`, runtime.GOOS, runtime.GOARCH, runtime.Compiler)
ua := fmt.Sprintf(`qingstor-sdk-go/%s (%s; %s)`, sdk.Version, version, system)
if qb.baseBuilder.operation.Config.AdditionalUserAgent != "" {
ua = fmt.Sprintf(`%s %s`, ua, qb.baseBuilder.operation.Config.AdditionalUserAgent)
}
httpRequest.Header.Set("User-Agent", ua)
}
if s := httpRequest.Header.Get("X-QS-Fetch-Source"); s != "" {
u, err := url.Parse(s)
if err != nil {
return fmt.Errorf("invalid HTTP header value: %s", s)
}
httpRequest.Header.Set("X-QS-Fetch-Source", u.String())
}
if qb.baseBuilder.operation.APIName == "Delete Multiple Objects" {
buffer := &bytes.Buffer{}
buffer.ReadFrom(httpRequest.Body)
httpRequest.Body = ioutil.NopCloser(bytes.NewReader(buffer.Bytes()))
md5Value := md5.Sum(buffer.Bytes())
httpRequest.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(md5Value[:]))
}
return nil
}
+39
View File
@@ -0,0 +1,39 @@
sudo: required
services:
- docker
language: go
go:
- "1.12"
env:
- GO111MODULE=on
cache:
directories:
- ${HOME}/source
before_install:
- pushd ${HOME}/source
- if [[ ! -d "./snips-v0.2.8" ]]; then
wget https://github.com/yunify/snips/releases/download/v0.2.8/snips-v0.2.8-linux_amd64.tar.gz &&
mkdir snips-v0.2.8 &&
pushd snips-v0.2.8 &&
tar -vxzf ../snips-v0.2.8-linux_amd64.tar.gz &&
popd;
fi
- pushd snips-v0.2.8 && sudo cp snips /usr/local/bin && popd
- popd
install:
- go get -u golang.org/x/lint/golint;
- git submodule init
before_script:
- make update
- make generate
script:
- make check
- make build test test-coverage
@@ -1,6 +1,39 @@
# Change Log
All notable changes to QingStor SDK for Go will be documented in this file.
## [v3.0.2] - 2019-7-15
### Fixed
- request/builder: Fix content length can't exceed int32 (#74)
## [v3.0.1] - 2019-7-11
### Fixed
- request/unpacker: Fix empty nginx error not parsed correctly (#72)
## [v3.0.0] - 2019-6-26
### Changed
- Use correct go module version
- From this release, go sdk will only provided by module, not zip anymore
## [v2.3.0] - 2019-4-25
### Added
- Add Content-Encoding header to put and post requests
- Add object cache control header
- Add `storage_class` in response element of API spec
## [v2.2.15] - 2018-8-19
### Changed
- Remove object content type detection
## [v2.2.14] - 2018-6-9
### Fixed
@@ -162,6 +195,11 @@ All notable changes to QingStor SDK for Go will be documented in this file.
- QingStor SDK for the Go programming language.
[v3.0.2]: https://github.com/yunify/qingstor-sdk-go/compare/v3.0.1...v3.0.2
[v3.0.1]: https://github.com/yunify/qingstor-sdk-go/compare/v3.0.0...v3.0.1
[v3.0.0]: https://github.com/yunify/qingstor-sdk-go/compare/v2.3.0...v3.0.0
[v2.3.0]: https://github.com/yunify/qingstor-sdk-go/compare/v2.2.15...v2.3.0
[v2.2.15]: https://github.com/yunify/qingstor-sdk-go/compare/v2.2.14...v2.2.15
[v2.2.14]: https://github.com/yunify/qingstor-sdk-go/compare/v2.2.13...v2.2.14
[v2.2.13]: https://github.com/yunify/qingstor-sdk-go/compare/v2.2.12...v2.2.13
[v2.2.12]: https://github.com/yunify/qingstor-sdk-go/compare/v2.2.11...v2.2.12
+1
View File
@@ -0,0 +1 @@
Xuanwo <xuanwo@yunify.com>
@@ -2,11 +2,9 @@ SHELL := /bin/bash
PREFIX=qingstor-sdk-go
VERSION=$(shell cat version.go | grep "Version\ =" | sed -e s/^.*\ //g | sed -e s/\"//g)
DIRS_TO_CHECK=$(shell ls -d */ | grep -vE "vendor|test")
PKGS_TO_CHECK=$(shell go list ./... | grep -v "/vendor/")
PKGS_TO_RELEASE=$(shell go list ./... | grep -vE "/vendor/|/test")
FILES_TO_RELEASE=$(shell find . -name "*.go" | grep -vE "/vendor/|/test|.*_test.go")
FILES_TO_RELEASE_WITH_VENDOR=$(shell find . -name "*.go" | grep -vE "/test|.*_test.go")
.PHONY: help
help:
@@ -20,8 +18,6 @@ help:
@echo " test-coverage to run test with coverage"
@echo " test-race to run test with race"
@echo " integration-test to run integration test"
@echo " release to build and release current version"
@echo " release-source to pack the source code"
@echo " clean to clean the coverage files"
.PHONY: all
@@ -39,7 +35,7 @@ format:
.PHONY: vet
vet:
@echo "Go tool vet, skipping vendor packages"
@go tool vet -all ${DIRS_TO_CHECK}
@for pkg in ${PKGS_TO_RELEASE}; do go vet -all $${pkg}; done;
@echo "Done"
.PHONY: lint
@@ -101,23 +97,6 @@ integration-test:
pushd "./test"; go test; popd
@echo "Done"
.PHONY: release
release: release-source release-source-with-vendor
.PHONY: release-source
release-source:
@echo "Pack the source code"
mkdir -p "release"
zip -FS "release/${PREFIX}-source-v${VERSION}.zip" ${FILES_TO_RELEASE}
@echo "Done"
.PHONY: release-source-with-vendor
release-source-with-vendor:
@echo "Pack the source code with vendor"
mkdir -p "release"
zip -FS "release/${PREFIX}-source-with-vendor-v${VERSION}.zip" ${FILES_TO_RELEASE_WITH_VENDOR}
@echo "Done"
.PHONY: clean
clean:
rm -rf $${PWD}/coverage
@@ -41,8 +41,8 @@ package main
import (
"fmt"
"github.com/yunify/qingstor-sdk-go/config"
qs "github.com/yunify/qingstor-sdk-go/service"
"github.com/yunify/qingstor-sdk-go/v3/config"
qs "github.com/yunify/qingstor-sdk-go/v3/service"
)
func main() {
@@ -26,8 +26,8 @@ import (
"gopkg.in/yaml.v2"
"github.com/yunify/qingstor-sdk-go/logger"
"github.com/yunify/qingstor-sdk-go/utils"
"github.com/yunify/qingstor-sdk-go/v3/logger"
"github.com/yunify/qingstor-sdk-go/v3/utils"
)
// A Config stores a configuration of this sdk.
+9
View File
@@ -0,0 +1,9 @@
module github.com/yunify/qingstor-sdk-go/v3
go 1.12
require (
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709
gopkg.in/yaml.v2 v2.2.2
)
+13
View File
@@ -0,0 +1,13 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14 h1:XeOYlK9W1uCmhjJSsY78Mcuh7MVkNjTzmHx1yBzizSU=
github.com/pengsrc/go-shared v0.2.1-0.20190131101655-1999055a4a14/go.mod h1:jVblp62SafmidSkvWrXyxAme3gaTfEtWwRPGz5cpvHg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -17,11 +17,19 @@
package builder
import (
"bytes"
"crypto/md5"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"time"
@@ -29,12 +37,14 @@ import (
"github.com/pengsrc/go-shared/convert"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/utils"
"github.com/yunify/qingstor-sdk-go/v3"
"github.com/yunify/qingstor-sdk-go/v3/logger"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
"github.com/yunify/qingstor-sdk-go/v3/utils"
)
// BaseBuilder is the base builder for all services.
type BaseBuilder struct {
// Builder is the request builder for QingStor service.
type Builder struct {
parsedURL string
parsedProperties *map[string]string
parsedQuery *map[string]string
@@ -47,54 +57,148 @@ type BaseBuilder struct {
}
// BuildHTTPRequest builds http request with an operation and an input.
func (b *BaseBuilder) BuildHTTPRequest(o *data.Operation, i *reflect.Value) (*http.Request, error) {
b.operation = o
b.input = i
func (qb *Builder) BuildHTTPRequest(o *data.Operation, i *reflect.Value) (*http.Request, error) {
qb.operation = o
qb.input = i
_, err := b.parse()
err := qb.parse()
if err != nil {
return nil, err
}
return b.build()
}
func (b *BaseBuilder) build() (*http.Request, error) {
httpRequest, err := http.NewRequest(b.operation.RequestMethod, b.parsedURL, b.parsedBody)
httpRequest, err := http.NewRequest(qb.operation.RequestMethod,
qb.parsedURL, qb.parsedBody)
if err != nil {
return nil, err
}
err = b.setupHeaders(httpRequest)
err = qb.setupHeaders(httpRequest)
if err != nil {
return nil, err
}
timestamp := convert.StringToTimestamp(httpRequest.Header.Get("Date"), convert.RFC822)
logger.Infof(nil, fmt.Sprintf(
"Built QingStor request: [%d] %s",
timestamp,
httpRequest.URL.String(),
))
logger.Infof(nil, fmt.Sprintf(
"QingStor request headers: [%d] %s",
timestamp,
fmt.Sprint(httpRequest.Header),
))
if qb.parsedBodyString != "" {
logger.Infof(nil, fmt.Sprintf(
"QingStor request body string: [%d] %s",
timestamp,
qb.parsedBodyString,
))
}
return httpRequest, nil
}
func (b *BaseBuilder) parse() (*BaseBuilder, error) {
err := b.parseRequestQueryAndHeaders()
func (qb *Builder) parse() error {
err := qb.parseRequestQueryAndHeaders()
if err != nil {
return b, err
return err
}
err = b.parseRequestBody()
err = qb.parseRequestBody()
if err != nil {
return b, err
return err
}
err = b.parseRequestProperties()
err = qb.parseRequestProperties()
if err != nil {
return b, err
return err
}
err = b.parseRequestURL()
err = qb.parseRequestURL()
if err != nil {
return b, err
return err
}
return b, nil
return nil
}
func (b *BaseBuilder) parseRequestQueryAndHeaders() error {
func (qb *Builder) parseRequestBody() error {
requestData := map[string]interface{}{}
if !qb.input.IsValid() {
return nil
}
fields := qb.input.Elem()
if !fields.IsValid() {
return nil
}
for i := 0; i < fields.NumField(); i++ {
location := fields.Type().Field(i).Tag.Get("location")
if location == "elements" {
name := fields.Type().Field(i).Tag.Get("name")
requestData[name] = fields.Field(i).Interface()
}
}
if len(requestData) != 0 {
dataValue, err := json.Marshal(requestData)
if err != nil {
return err
}
qb.parsedBodyString = string(dataValue)
qb.parsedBody = strings.NewReader(qb.parsedBodyString)
(*qb.parsedHeaders)["Content-Type"] = "application/json"
} else {
value := fields.FieldByName("Body")
if value.IsValid() {
switch value.Interface().(type) {
case string:
if value.String() != "" {
qb.parsedBodyString = value.String()
qb.parsedBody = strings.NewReader(value.String())
}
case io.Reader:
if value.Interface().(io.Reader) != nil {
qb.parsedBody = value.Interface().(io.Reader)
}
}
}
}
return nil
}
func (qb *Builder) parseRequestProperties() error {
propertiesMap := map[string]string{}
qb.parsedProperties = &propertiesMap
if qb.operation.Properties != nil {
fields := reflect.ValueOf(qb.operation.Properties).Elem()
if fields.IsValid() {
for i := 0; i < fields.NumField(); i++ {
switch value := fields.Field(i).Interface().(type) {
case *string:
if value != nil {
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = *value
}
case *int:
if value != nil {
numberString := strconv.Itoa(int(*value))
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = numberString
}
}
}
}
}
return nil
}
func (qb *Builder) parseRequestQueryAndHeaders() error {
requestQuery := map[string]string{}
requestHeaders := map[string]string{}
maps := map[string](map[string]string){
@@ -102,14 +206,14 @@ func (b *BaseBuilder) parseRequestQueryAndHeaders() error {
"headers": requestHeaders,
}
b.parsedQuery = &requestQuery
b.parsedHeaders = &requestHeaders
qb.parsedQuery = &requestQuery
qb.parsedHeaders = &requestHeaders
if !b.input.IsValid() {
if !qb.input.IsValid() {
return nil
}
fields := b.input.Elem()
fields := qb.input.Elem()
if !fields.IsValid() {
return nil
}
@@ -154,89 +258,44 @@ func (b *BaseBuilder) parseRequestQueryAndHeaders() error {
return nil
}
func (b *BaseBuilder) parseRequestBody() error {
requestData := map[string]interface{}{}
func (qb *Builder) parseRequestURL() error {
config := qb.operation.Config
if !b.input.IsValid() {
return nil
zone := (*qb.parsedProperties)["zone"]
port := strconv.Itoa(config.Port)
endpoint := config.Protocol + "://" + config.Host + ":" + port
if zone != "" {
endpoint = config.Protocol + "://" + zone + "." + config.Host + ":" + port
}
fields := b.input.Elem()
if !fields.IsValid() {
return nil
requestURI := qb.operation.RequestURI
for key, value := range *qb.parsedProperties {
endpoint = strings.Replace(endpoint, "<"+key+">", utils.URLQueryEscape(value), -1)
requestURI = strings.Replace(requestURI, "<"+key+">", utils.URLQueryEscape(value), -1)
}
requestURI = regexp.MustCompile(`/+`).ReplaceAllString(requestURI, "/")
requestURL, err := url.Parse(endpoint + requestURI)
if err != nil {
return err
}
for i := 0; i < fields.NumField(); i++ {
location := fields.Type().Field(i).Tag.Get("location")
if location == "elements" {
name := fields.Type().Field(i).Tag.Get("name")
requestData[name] = fields.Field(i).Interface()
}
}
if len(requestData) != 0 {
dataValue, err := json.Marshal(requestData)
if err != nil {
return err
}
b.parsedBodyString = string(dataValue)
b.parsedBody = strings.NewReader(b.parsedBodyString)
(*b.parsedHeaders)["Content-Type"] = "application/json"
} else {
value := fields.FieldByName("Body")
if value.IsValid() {
switch value.Interface().(type) {
case string:
if value.String() != "" {
b.parsedBodyString = value.String()
b.parsedBody = strings.NewReader(value.String())
}
case io.Reader:
if value.Interface().(io.Reader) != nil {
b.parsedBody = value.Interface().(io.Reader)
}
}
if qb.parsedQuery != nil {
queryValue := requestURL.Query()
for key, value := range *qb.parsedQuery {
queryValue.Set(key, value)
}
requestURL.RawQuery = queryValue.Encode()
}
qb.parsedURL = requestURL.String()
return nil
}
func (b *BaseBuilder) parseRequestProperties() error {
propertiesMap := map[string]string{}
b.parsedProperties = &propertiesMap
func (qb *Builder) setupHeaders(httpRequest *http.Request) error {
if qb.parsedHeaders != nil {
if b.operation.Properties != nil {
fields := reflect.ValueOf(b.operation.Properties).Elem()
if fields.IsValid() {
for i := 0; i < fields.NumField(); i++ {
switch value := fields.Field(i).Interface().(type) {
case *string:
if value != nil {
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = *value
}
case *int:
if value != nil {
numberString := strconv.Itoa(int(*value))
propertiesMap[fields.Type().Field(i).Tag.Get("name")] = numberString
}
}
}
}
}
return nil
}
func (b *BaseBuilder) parseRequestURL() error {
return nil
}
func (b *BaseBuilder) setupHeaders(httpRequest *http.Request) error {
if b.parsedHeaders != nil {
for headerKey, headerValue := range *b.parsedHeaders {
for headerKey, headerValue := range *qb.parsedHeaders {
for _, r := range headerValue {
if r > unicode.MaxASCII {
headerValue = utils.URLQueryEscape(headerValue)
@@ -250,7 +309,7 @@ func (b *BaseBuilder) setupHeaders(httpRequest *http.Request) error {
if httpRequest.Header.Get("Content-Length") == "" {
var length int64
switch body := b.parsedBody.(type) {
switch body := qb.parsedBody.(type) {
case nil:
length = 0
case io.Seeker:
@@ -277,7 +336,7 @@ func (b *BaseBuilder) setupHeaders(httpRequest *http.Request) error {
httpRequest.Header.Set("Content-Length", "0")
}
}
length, err := strconv.Atoi(httpRequest.Header.Get("Content-Length"))
length, err := strconv.ParseInt(httpRequest.Header.Get("Content-Length"), 10, 64)
if err != nil {
return err
}
@@ -287,5 +346,32 @@ func (b *BaseBuilder) setupHeaders(httpRequest *http.Request) error {
httpRequest.Header.Set("Date", convert.TimeToString(time.Now(), convert.RFC822))
}
if httpRequest.Header.Get("User-Agent") == "" {
version := fmt.Sprintf(`Go v%s`, strings.Replace(runtime.Version(), "go", "", -1))
system := fmt.Sprintf(`%s_%s_%s`, runtime.GOOS, runtime.GOARCH, runtime.Compiler)
ua := fmt.Sprintf(`qingstor-sdk-go/%s (%s; %s)`, sdk.Version, version, system)
if qb.operation.Config.AdditionalUserAgent != "" {
ua = fmt.Sprintf(`%s %s`, ua, qb.operation.Config.AdditionalUserAgent)
}
httpRequest.Header.Set("User-Agent", ua)
}
if s := httpRequest.Header.Get("X-QS-Fetch-Source"); s != "" {
u, err := url.Parse(s)
if err != nil {
return fmt.Errorf("invalid HTTP header value: %s", s)
}
httpRequest.Header.Set("X-QS-Fetch-Source", u.String())
}
if qb.operation.APIName == "Delete Multiple Objects" {
buffer := &bytes.Buffer{}
buffer.ReadFrom(httpRequest.Body)
httpRequest.Body = ioutil.NopCloser(bytes.NewReader(buffer.Bytes()))
md5Value := md5.Sum(buffer.Bytes())
httpRequest.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(md5Value[:]))
}
return nil
}
@@ -17,7 +17,7 @@
package data
import (
"github.com/yunify/qingstor-sdk-go/config"
"github.com/yunify/qingstor-sdk-go/v3/config"
)
// Operation stores information of an operation.
@@ -26,11 +26,11 @@ import (
"github.com/pengsrc/go-shared/convert"
"github.com/yunify/qingstor-sdk-go/logger"
"github.com/yunify/qingstor-sdk-go/request/builder"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/request/signer"
"github.com/yunify/qingstor-sdk-go/request/unpacker"
"github.com/yunify/qingstor-sdk-go/v3/logger"
"github.com/yunify/qingstor-sdk-go/v3/request/builder"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
"github.com/yunify/qingstor-sdk-go/v3/request/signer"
"github.com/yunify/qingstor-sdk-go/v3/request/unpacker"
)
// A Request can build, sign, send and unpack API request.
@@ -168,7 +168,7 @@ func (r *Request) check() error {
}
func (r *Request) build() error {
b := &builder.QingStorBuilder{}
b := &builder.Builder{}
httpRequest, err := b.BuildHTTPRequest(r.Operation, r.Input)
if err != nil {
return err
@@ -27,8 +27,8 @@ import (
"github.com/pengsrc/go-shared/convert"
"github.com/yunify/qingstor-sdk-go/logger"
"github.com/yunify/qingstor-sdk-go/utils"
"github.com/yunify/qingstor-sdk-go/v3/logger"
"github.com/yunify/qingstor-sdk-go/v3/utils"
)
// QingStorSigner is the http request signer for QingStor service.
@@ -27,8 +27,8 @@ import (
"github.com/pengsrc/go-shared/convert"
"github.com/yunify/qingstor-sdk-go/logger"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/v3/logger"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
)
// BaseUnpacker is the base unpacker for all services.
@@ -19,11 +19,13 @@ package unpacker
import (
"bytes"
"encoding/json"
"io"
"net/http"
"reflect"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/request/errors"
"github.com/yunify/qingstor-sdk-go/v3/logger"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
"github.com/yunify/qingstor-sdk-go/v3/request/errors"
)
// QingStorUnpacker is the response unpacker for QingStor service.
@@ -58,27 +60,43 @@ func (qu *QingStorUnpacker) UnpackHTTPRequest(o *data.Operation, r *http.Respons
}
func (qu *QingStorUnpacker) parseError() error {
if !qu.baseUnpacker.isResponseRight() {
if qu.baseUnpacker.httpResponse.Header.Get("Content-Type") == "application/json" {
buffer := &bytes.Buffer{}
buffer.ReadFrom(qu.baseUnpacker.httpResponse.Body)
qu.baseUnpacker.httpResponse.Body.Close()
qsError := &errors.QingStorError{}
if buffer.Len() > 0 {
err := json.Unmarshal(buffer.Bytes(), qsError)
if err != nil {
return err
}
}
qsError.StatusCode = qu.baseUnpacker.httpResponse.StatusCode
if qsError.RequestID == "" {
qsError.RequestID = qu.baseUnpacker.httpResponse.Header.Get(http.CanonicalHeaderKey("X-QS-Request-ID"))
}
return qsError
}
if qu.baseUnpacker.isResponseRight() {
return nil
}
return nil
// QingStor nginx could refuse user's request directly and only return status code.
// We should handle this and build a qingstor error with message.
if qu.baseUnpacker.httpResponse.Header.Get("Content-Type") != "application/json" {
qsError := &errors.QingStorError{
StatusCode: qu.baseUnpacker.httpResponse.StatusCode,
Message: http.StatusText(qu.baseUnpacker.httpResponse.StatusCode),
}
return qsError
}
buffer := &bytes.Buffer{}
_, err := io.Copy(buffer, qu.baseUnpacker.httpResponse.Body)
if err != nil {
logger.Errorf(nil, "Copy from error response body failed for %v", err)
return err
}
err = qu.baseUnpacker.httpResponse.Body.Close()
if err != nil {
logger.Errorf(nil, "Close error response body failed for %v", err)
return err
}
qsError := &errors.QingStorError{}
if buffer.Len() > 0 {
err := json.Unmarshal(buffer.Bytes(), qsError)
if err != nil {
return err
}
}
qsError.StatusCode = qu.baseUnpacker.httpResponse.StatusCode
if qsError.RequestID == "" {
qsError.RequestID = qu.baseUnpacker.httpResponse.Header.Get(http.CanonicalHeaderKey("X-QS-Request-ID"))
}
return qsError
}
@@ -23,10 +23,10 @@ import (
"strings"
"time"
"github.com/yunify/qingstor-sdk-go/config"
"github.com/yunify/qingstor-sdk-go/request"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/request/errors"
"github.com/yunify/qingstor-sdk-go/v3/config"
"github.com/yunify/qingstor-sdk-go/v3/request"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
"github.com/yunify/qingstor-sdk-go/v3/request/errors"
)
var _ fmt.State
@@ -1080,6 +1080,8 @@ type ListObjectsOutput struct {
CommonPrefixes []*string `json:"common_prefixes,omitempty" name:"common_prefixes" location:"elements"`
// Delimiter that specified in request parameters
Delimiter *string `json:"delimiter,omitempty" name:"delimiter" location:"elements"`
// Indicate if these are more results in the next page
HasMore *bool `json:"has_more,omitempty" name:"has_more" location:"elements"`
// Object keys
Keys []*KeyType `json:"keys,omitempty" name:"keys" location:"elements"`
// Limit that specified in request parameters
@@ -23,10 +23,10 @@ import (
"strings"
"time"
"github.com/yunify/qingstor-sdk-go/config"
"github.com/yunify/qingstor-sdk-go/request"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/request/errors"
"github.com/yunify/qingstor-sdk-go/v3/config"
"github.com/yunify/qingstor-sdk-go/v3/request"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
"github.com/yunify/qingstor-sdk-go/v3/request/errors"
)
var _ fmt.State
@@ -963,6 +963,10 @@ func (s *Bucket) PutObjectRequest(objectKey string, input *PutObjectInput) (*req
// PutObjectInput presents input for PutObject.
type PutObjectInput struct {
// Object cache control
CacheControl *string `json:"Cache-Control,omitempty" name:"Cache-Control" location:"headers"`
// Object content encoding
ContentEncoding *string `json:"Content-Encoding,omitempty" name:"Content-Encoding" location:"headers"`
// Object content size
ContentLength *int64 `json:"Content-Length" name:"Content-Length" location:"headers"` // Required
// Object MD5sum
@@ -20,9 +20,9 @@ package service
import (
"net/http"
"github.com/yunify/qingstor-sdk-go/config"
"github.com/yunify/qingstor-sdk-go/request"
"github.com/yunify/qingstor-sdk-go/request/data"
"github.com/yunify/qingstor-sdk-go/v3/config"
"github.com/yunify/qingstor-sdk-go/v3/request"
"github.com/yunify/qingstor-sdk-go/v3/request/data"
)
var _ http.Header
@@ -20,7 +20,7 @@ import (
"fmt"
"time"
"github.com/yunify/qingstor-sdk-go/request/errors"
"github.com/yunify/qingstor-sdk-go/v3/request/errors"
)
// Properties presents the service properties.
@@ -343,6 +343,8 @@ type KeyType struct {
Modified *int `json:"modified,omitempty" name:"modified"`
// Object content size
Size *int64 `json:"size,omitempty" name:"size"`
// Object storage class
StorageClass *string `json:"storage_class,omitempty" name:"storage_class"`
}
// Validate validates the Key.
@@ -3,12 +3,9 @@ package utils
import (
"context"
"net"
"sync"
"time"
)
var connPool sync.Pool
type netConn net.Conn
type netDialer net.Dialer
@@ -71,10 +68,7 @@ func NewConn(c netConn) *Conn {
if ok {
return conn
}
conn, ok = connPool.Get().(*Conn)
if !ok {
conn = new(Conn)
}
conn = new(Conn)
conn.netConn = c
return conn
}
@@ -119,7 +113,6 @@ func (c Conn) Close() (err error) {
return nil
}
err = c.netConn.Close()
connPool.Put(c)
c.netConn = nil
c.readTimeout = 0
c.writeTimeout = 0
@@ -20,4 +20,4 @@
package sdk
// Version number.
const Version = "2.2.15"
const Version = "3.0.2"